package cn.huiyunche.base.service.interfaces.impl;

import cn.huiyunche.base.service.constant.App;
import cn.huiyunche.base.service.constant.BVehicleConstant;
import cn.huiyunche.base.service.constant.QiniuConstant;
import cn.huiyunche.base.service.constant.TmsUrlConstant;
import cn.huiyunche.base.service.enums.*;
import cn.huiyunche.base.service.form.AttachForm;
import cn.huiyunche.base.service.framework.redis.MindsJedisConnectionFactory;
import cn.huiyunche.base.service.framework.utils.HYCUtils;
import cn.huiyunche.base.service.framework.utils.QiniuUtils;
import cn.huiyunche.base.service.interfaces.*;
import cn.huiyunche.base.service.mappers.*;
import cn.huiyunche.base.service.mappers.ext.CWaybillViewMapper;
import cn.huiyunche.base.service.mappers.ext.SUserDevicesExtMapper;
import cn.huiyunche.base.service.mappers.ext.SWaybillViewMapper;
import cn.huiyunche.base.service.mappers.ext.WaybillMapper;
import cn.huiyunche.base.service.model.*;
import cn.huiyunche.base.service.utils.*;
import cn.huiyunche.base.service.vo.*;
import cn.huiyunche.base.service.vo.detail.DeReDetailVo;
import cn.huiyunche.tools.basic.Collections3;
import cn.huiyunche.tools.basic.exceptions.BusinessException;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import io.jsonwebtoken.lang.Collections;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 运单Service 实现类
 *
 * @author Administrator
 */
@Service
public class CWaybillServiceImpl implements CWaybillService {

    private static final Logger LOGGER = LoggerFactory.getLogger(CWaybillServiceImpl.class);

    private static String REDIS_LOCK_WAYBILL_GRAB_PRE = "lock:waybill:grab:";

    //redis
    private static Jedis jedis = null;

    //派单关系列表key
    private static final String CW_WITH_USER = "cw_with_user";

    //派单关系信息连接符
    private static final String CW_WITH_USER_INFO_CONCAT_SYMBOL = ":";

    @Autowired
    private SOrderMapper orderMapper = null;

    @Autowired
    private CWaybillMapper cWaybillMapper = null;

    @Autowired
    private MindsJedisConnectionFactory connectionFactory;

    @Autowired
    private UserService userService = null;

    @Autowired
    private CAccntTurnOverService cAccntTurnOverService = null;

    @Autowired
    private SWaybillViewMapper sWaybillViewMapper = null;

    @Autowired
    private CWaybillAttachMapper cWaybillAttachMapper = null;

    @Autowired
    private DriverCertInfoService driverCertInfoService = null;

    @Autowired
    private RedisCacheManager redisCacheManager;

    @Autowired
    private SOrderService orderService = null;

    @Autowired
    private BAreaService areaService = null;

    @Autowired
    private TruckInfoService truckInfoService = null;

    @Autowired
    private CWaybillContactsService cWaybillContactsService = null;

    @Autowired
    private SServiceOrderVehicleService sServiceOrderVehicleService = null;

    @Autowired
    private BVehicleService bVehicleService = null;

    @Autowired
    private BVehicleBrandService bVehicleBrandService = null;

    @Autowired
    private CWaybillDetailMapper cWaybillDetailMapper = null;

    @Autowired
    private CWaybillStatusLogService cWaybillStatusLogService = null;

    @Autowired
    private GDMapService mapService = null;

    @Autowired
    private BFeeTypeService bFeeTypeService = null;

    @Autowired
    private VehicleClassService vehicleClassService = null;

    @Autowired
    private BVehicleMapper bVehicleMapper = null;

    @Autowired
    private CWaybillViewMapper cWaybillViewMapper = null;

    @Autowired
    private WaybillMapper waybillMapper = null;

    @Autowired
    private CWaybillAddressService cWaybillAddressService = null;

    @Autowired
    private SServiceOrderService sServiceOrderService = null;

    @Autowired
    private SServiceOrderMapper serviceOrderMapper = null;

    @Autowired
    private WaybillBidService waybillBidService = null;

    @Autowired
    private SServiceOrderFeedetailService sServiceOrderFeedetailService;

    @Autowired
    private BFeeModelService bFeeModelService;

    @Autowired
    private SServiceOrderStatusLogService sServiceOrderStatusLogService = null;

    @Autowired
    private JPushService jPushService = null;

    @Autowired
    private SUserDevicesMapper sUserDevicesMapper = null;

    @Autowired
    private SUserMapper sUserMapper = null;

    @Autowired
    private SUserDevicesExtMapper sUserDevicesExtMapper = null;

    @Autowired
    private BAreaService bAreaService = null;

    @Autowired
    private BCompanyUserService bCompanyUserService = null;

    @Autowired
    private CompanyService companyService = null;

    @Autowired
    private CWaybillVeneerService cWaybillVeneerService;

    @Autowired
    private SendMessageService sendMessageService = null;

    private CompanyService getCompanyService() {
        return this.companyService;
    }

    private BCompanyUserService getBCompanyUserService() {
        return this.bCompanyUserService;
    }

    private BAreaService getBAreaService() {
        return bAreaService;
    }

    private SUserDevicesExtMapper getSUserDevicesExtMapper() {
        return sUserDevicesExtMapper;
    }

    private SUserMapper getSUserMapper() {
        return this.sUserMapper;
    }

    private SUserDevicesMapper getSUserDevicesMapper() {
        return this.sUserDevicesMapper;
    }

    private JPushService getJPushService() {
        return this.jPushService;
    }

    private SendMessageService getSendMessageService() {
        return this.sendMessageService;
    }

    private SServiceOrderStatusLogService getSServiceOrderStatusLogService() {
        return this.sServiceOrderStatusLogService;
    }

    private DriverCertInfoService getDriverCertInfoService() {
        return this.driverCertInfoService;
    }

    private CWaybillAttachMapper getCWaybillAttachMapper() {
        return this.cWaybillAttachMapper;
    }

    private SWaybillViewMapper getSWaybillViewMapper() {
        return this.sWaybillViewMapper;
    }

    private CAccntTurnOverService getCAccntTurnOverService() {
        return this.cAccntTurnOverService;
    }

    private SOrderMapper getSOrderMapper() {
        return this.orderMapper;
    }

    @Autowired
    private CWaybillAttachService cWaybillAttachService;

    @Autowired
    private SServiceOrderTrailMapper sServiceOrderTrailMapper = null;

    private SServiceOrderTrailMapper getSServiceOrderTrailMapper() {
        return this.sServiceOrderTrailMapper;
    }

    private WaybillBidService getWaybillBidService() {
        return this.waybillBidService;
    }

    private SOrderService getSOrderService() {
        return this.orderService;
    }

    private SServiceOrderService getSServiceOrderService() {
        return this.sServiceOrderService;
    }

    private SServiceOrderMapper getSServiceOrderMapper() {
        return serviceOrderMapper;
    }

    private CWaybillAddressService getCWaybillAddressService() {
        return this.cWaybillAddressService;
    }

    private WaybillMapper getWaybillMapper() {
        return this.waybillMapper;
    }

    private CWaybillViewMapper getCWaybillViewMapper() {
        return this.cWaybillViewMapper;
    }

    private BVehicleMapper getBVehicleMapper() {
        return this.bVehicleMapper;
    }

    private VehicleClassService getVehicleClassService() {
        return this.vehicleClassService;
    }

    private BAreaService getAreaService() {
        return this.areaService;
    }

    private UserService getUserService() {
        return this.userService;
    }

    private CWaybillMapper getCWaybillMapper() {
        return this.cWaybillMapper;
    }

    private TruckInfoService getTruckInfoService() {
        return this.truckInfoService;
    }

    private CWaybillContactsService getCWaybillContactsService() {
        return this.cWaybillContactsService;
    }

    private SServiceOrderVehicleService getSServiceOrderVehicleService() {
        return this.sServiceOrderVehicleService;
    }

    private BVehicleService getBVehicleService() {
        return this.bVehicleService;
    }

    private BVehicleBrandService getBVehicleBrandService() {
        return this.bVehicleBrandService;
    }

    private CWaybillDetailMapper getCWaybillDetailMapper() {
        return this.cWaybillDetailMapper;
    }

    private CWaybillStatusLogService getCWaybillStatusLogService() {
        return this.cWaybillStatusLogService;
    }

    private BFeeTypeService getBFeeTypeService() {
        return this.bFeeTypeService;
    }

    @Autowired
    private BStowageVehicleService bStowageVehicleService;

    /**
     * @param orderid 传入当前时间
     * @return
     * @Title: getSurplusTimeByOrder
     * @Description: 返回剩余时间 秒
     * @return: Long
     */
    private Long getSurplusTimeByOrder(String orderid) {
        String key = App.OrderPublishOrderidsKey;
        Long surplusTime = 0L;
        Jedis jedis = connectionFactory.fetchJedisConnector();
        try {
            String createDate = jedis.hget(key, orderid);
            if (StringUtils.isNotBlank(createDate)) {
                Long lngCreateDate = Long.valueOf(createDate);
                surplusTime = ((lngCreateDate + App.ORDER_EFFECTIVE_TIME * 1000) - new Date().getTime()) / 1000;
                if (surplusTime < 0) {
                    surplusTime = 0L;
                }
            }
        } catch (Exception e) {
            LOGGER.error("OrderServiceImpl.getSurplusTimeByOrder error : {}", e);
            throw new BusinessException("查询订单" + orderid + "剩余时间失败！");
        } finally {
            jedis.close();
        }
        return surplusTime;
    }

    @Override
    public WaybillNewVo getById(Long id) {
        if (id == null || id == 0) {
            LOGGER.error("id is null");
            throw new BusinessException("运单id不能为空！");
        }
        try {
            WaybillNewVo vo = this.getSWaybillViewMapper().selectById(id);

            // 查询运单信息
            if (vo == null) {
                LOGGER.error("vo is null");
                throw new BusinessException("获取运单信息失败!");
            }

            // 获取车型logo
            List<CWaybillDetailVo> vehicles = vo.getVehicles();
            if (CollectionUtils.isNotEmpty(vehicles)) {
                VehicleBrandVo brand = new VehicleBrandVo();
                for (int i = 0; i < vehicles.size(); i++) {
                    brand = vehicles.get(i).getBrand();
                    if (brand != null) {
                        if (StringUtils.isNotBlank(brand.getLogo())) {
                            /** brand.setLogo(QiniuUtils.generateDownloadTicket(
                             HYCUtils.getConstantPropertiesLoader().getProperty(QiniuConstant.QINIU_LOGO_BUCKET),
                             brand.getLogo(), "1", "200", "200")); */
                            vehicles.get(i).setBrandLogo(QiniuUtils.generateDownloadTicket(
                                    HYCUtils.getConstantPropertiesLoader().getProperty(QiniuConstant.QINIU_LOGO_BUCKET),
                                    brand.getLogo(), "1", "200", "200"));
                        }
                    }
                }
                vo.setDetail(vehicles.size() + "辆");
            }

            // 处理图片
            this.buildAttach(vo);

            long seconds = this.getSurplusTimeByOrder(vo.getId().toString());
            vo.setPostTimeRemaining((long) Math.ceil(seconds == 0 ? 0 : seconds / 60));
            return vo;
        } catch (Exception e) {
            LOGGER.error("select cwaybill detail error : {}.", e);
            throw new BusinessException("查询运单明细异常");
        }
    }

    private void buildAttach(WaybillNewVo vo) {
        LOGGER.info("buildAttach params : {}", vo);
        // 发车照片
        List<AttachVo> loadPics = vo.getSendPics();
        if (CollectionUtils.isNotEmpty(loadPics)) {
            AttachVo attach = new AttachVo();
            for (int i = 0; i < loadPics.size(); i++) {
                attach = loadPics.get(i);
                attach.setPicKey(QiniuUtils.generateDownloadTicket(attach.getPicKey(), ""));
                attach.setTypeText(AttachTypeEnum.getByValue(attach.getType()).getText());
            }
        }

        // 交车照片
        List<AttachVo> unloadPics = vo.getDeliverPics();
        if (CollectionUtils.isNotEmpty(unloadPics)) {
            AttachVo attach = new AttachVo();
            for (int i = 0; i < unloadPics.size(); i++) {
                attach = unloadPics.get(i);
                attach.setPicKey(QiniuUtils.generateDownloadTicket(attach.getPicKey(), ""));
                attach.setTypeText(AttachTypeEnum.getByValue(attach.getType()).getText());
            }
        }
    }

    @Override
    public int updateCompleteOrder(Long id) {
        LOGGER.info("updateCompleteOrder param : {}", id);
        SOrder order = this.getSOrderMapper().selectByPrimaryKey(id);
        if (order == null) {
            throw new BusinessException("订单不存在！");
        }

        // 若运单状态为已交车且付款状态为已付全款则更新订单为已完成
        if (order.getStatus() == COrderStatusEnum.COMPLETED.getValue()
                && order.getPayStatus() == PaymentStatusEnum.ALREADY_PAID.getValue()) {
            order.setStatus(SServiceOrderStatusEnum.DONE.getValue());

            // 写入订单费用记录到账单明细
            SUser user = this.getUserService().getById(order.getUserId());
            List<CTurnover> accntDetails = new ArrayList<>();
            // 订单费用
            CTurnover orderDetail = new CTurnover();
            // orderDetail.setAccountId(order.getUserId().toString());
            // orderDetail.setAccountName(user.getName());
            orderDetail.setUserType(user.getUserType());
            orderDetail.setOrderId(order.getId());
            // orderDetail.setOrderPrice(order.getActualCost());
            // orderDetail.setFeetype(AccFeetypeEnum.ORDER.getValue());
            orderDetail.setCreateTime(new Date());
            accntDetails.add(orderDetail);

            // 报价费用
            // SWaybillQuote quote =
            // quoteService.selectQuoteByOrderId(order.getId());
            // SUser u = userService.getById(quote.getUserId());
            CTurnover quoteDetail = new CTurnover();
            // orderDetail.setAccountId(u.getId().toString());
            // orderDetail.setAccountName(u.getName());
            // orderDetail.setUserType(u.getUserType());
            orderDetail.setOrderId(order.getId());
            // orderDetail.setOrderPrice(quote.getPrice());
            // orderDetail.setFeetype(AccFeetypeEnum.ORDER.getValue());
            orderDetail.setCreateTime(new Date());
            accntDetails.add(quoteDetail);

            this.getCAccntTurnOverService().addDetailsAndLedger(accntDetails, 0);

            return this.getSOrderMapper().updateByPrimaryKeySelective(order);
        }
        return 0;
    }

    /**
     * 承运端 查询运单 通用方法
     *
     * @param page
     * @param statusList
     * @return
     */
    public Map<String, Object> getCWaybillList(PageVo page, List<Integer> statusList, Boolean isVeneer) throws Exception {
        LOGGER.info("select stan cwaybill list params page : {}, statusList : {}.", page, statusList);
        Map<String, Object> map = new HashMap<>();
        UserVo currentUserVo = this.getUserService().getCurrentUserVo();
        Long userId = currentUserVo.getId();
        try {
            Integer userType = currentUserVo.getType();
            List<Long> userIdList = new ArrayList<>();
            if (userType == UserTypeEnum.COMPANY.getValue()) {
                Long companyId = this.getBCompanyUserService().getCompanyIdByUserId(userId);
                List<BCompanyUser> BCompanyUserList = this.getBCompanyUserService().getListByCompanyId(companyId);

                for (BCompanyUser bCompanyUser : BCompanyUserList) {
                    userIdList.add(bCompanyUser.getUserId());
                }
            } else {
                userIdList.add(userId);
            }
            LOGGER.info("select stan cwaybill list params page : {}, statusList : {}, currentUser : {}.", page, statusList, userId);

            Map<String, Object> paramsMap = new HashMap<>();
            if (!statusList.contains(WaybillStatusEnum.WAITBID.getValue())) {
                if (CollectionUtils.isNotEmpty(userIdList)) {
                    paramsMap.put("userIdList", userIdList);
                }
            }
            if (CollectionUtils.isNotEmpty(statusList)) {
                paramsMap.put("statusList", statusList);
            }

            String orderByClause = StringUtils.isNotBlank(page.getOrder()) == true ? page.getOrder()
                    : " w.update_time DESC ";
            paramsMap.put("limitStart", page.getStartIndex());
            paramsMap.put("limitEnd", page.getPageSize());
            paramsMap.put("orderByClause", orderByClause);
            paramsMap.put("isVeneer", isVeneer);

            page.setTotalRecord(this.getSWaybillViewMapper().countByGrabAlready(paramsMap));
            List<WaybillNewVo> waybills = this.getSWaybillViewMapper().selectByGrabAlready(paramsMap);
            List<Long> waybillId = new ArrayList<>();
            List<WaybillNewVo> waybills2 = new ArrayList<>();
            for (WaybillNewVo waybillNewVo : waybills) {
                if (!waybillId.contains(waybillNewVo.getId())) {
                    waybillId.add(waybillNewVo.getId());
                    waybills2.add(waybillNewVo);
                }
            }
            for (int i = 0; i < waybills2.size(); i++) {
                WaybillNewVo vo = waybills2.get(i);
                if (vo != null) {
                    // 车辆信息
                    List<CWaybillDetailVo> vehicles = vo.getVehicles();
                    if (CollectionUtils.isNotEmpty(vehicles)) {
                        if (vehicles.size() == 1) {
                            vo.setDetail(vehicles.get(0).getBrandName() + "1辆");
                        } else {
                            List<Long> brands = new ArrayList<Long>();
                            for (int j = 0; j < vehicles.size(); j++) {
                                if (!brands.contains(vehicles.get(j).getBrandId())) {
                                    brands.add(vehicles.get(j).getBrandId());
                                }
                            }
                            StringBuffer s = new StringBuffer();
                            s.append(brands.size()).append("个品牌 ").append(vehicles.size()).append("辆车").toString();
                            vo.setDetail(s.toString());
                        }
                    }
                }
            }
            map.put("waybills", waybills2);
            map.put("page", page);
        } catch (Exception e) {
            LOGGER.error("select cwaybill no grab list error : {}.", e);
            throw new BusinessException("查询运单待接单列表异常");
        }
        return map;
    }

    /**
     * 承运端 查询运单 通用方法
     *
     * @param page
     * @param statusList
     * @return
     */
    public Map<String, Object> getCWaybillList(PageVo page, List<Integer> statusList) throws Exception {
        LOGGER.info("select stan cwaybill list params page : {}, statusList : {}.", page, statusList);
        Map<String, Object> map = new HashMap<>();
        UserVo currentUserVo = this.getUserService().getCurrentUserVo();
        Long userId = currentUserVo.getId();
        try {
            Integer userType = currentUserVo.getType();
            List<Long> userIdList = new ArrayList<>();
            if (userType == UserTypeEnum.COMPANY.getValue()) {
                Long companyId = this.getBCompanyUserService().getCompanyIdByUserId(userId);
                List<BCompanyUser> BCompanyUserList = this.getBCompanyUserService().getListByCompanyId(companyId);

                for (BCompanyUser bCompanyUser : BCompanyUserList) {
                    userIdList.add(bCompanyUser.getUserId());
                }
            } else {
                userIdList.add(userId);
            }
            LOGGER.info("select stan cwaybill list params page : {}, statusList : {}, currentUser : {}.", page, statusList, userId);

            Map<String, Object> paramsMap = new HashMap<>();
            if (!statusList.contains(WaybillStatusEnum.WAITBID.getValue())) {
                if (CollectionUtils.isNotEmpty(userIdList)) {
                    paramsMap.put("userIdList", userIdList);
                }
            }
            if (CollectionUtils.isNotEmpty(statusList)) {
                paramsMap.put("statusList", statusList);
            }

            String orderByClause = StringUtils.isNotBlank(page.getOrder()) == true ? page.getOrder()
                    : " w.update_time DESC ";
            paramsMap.put("limitStart", page.getStartIndex());
            paramsMap.put("limitEnd", page.getPageSize());
            paramsMap.put("orderByClause", orderByClause);
            //paramsMap.put("isVeneer", isVeneer);

            page.setTotalRecord(this.getSWaybillViewMapper().countByGrabAlready(paramsMap));
            List<WaybillNewVo> waybills = this.getSWaybillViewMapper().selectByGrabAlready(paramsMap);
            List<Long> waybillId = new ArrayList<>();
            List<WaybillNewVo> waybills2 = new ArrayList<>();
            for (WaybillNewVo waybillNewVo : waybills) {
                if (!waybillId.contains(waybillNewVo.getId())) {
                    waybillId.add(waybillNewVo.getId());
                    waybills2.add(waybillNewVo);
                }
            }
            for (int i = 0; i < waybills2.size(); i++) {
                WaybillNewVo vo = waybills2.get(i);
                if (vo != null) {
                    // 车辆信息
                    List<CWaybillDetailVo> vehicles = vo.getVehicles();
                    if (CollectionUtils.isNotEmpty(vehicles)) {
                        if (vehicles.size() == 1) {
                            vo.setDetail(vehicles.get(0).getBrandName() + "1辆");
                        } else {
                            List<Long> brands = new ArrayList<Long>();
                            for (int j = 0; j < vehicles.size(); j++) {
                                if (!brands.contains(vehicles.get(j).getBrandId())) {
                                    brands.add(vehicles.get(j).getBrandId());
                                }
                            }
                            StringBuffer s = new StringBuffer();
                            s.append(brands.size()).append("个品牌 ").append(vehicles.size()).append("辆车").toString();
                            vo.setDetail(s.toString());
                        }
                    }
                }
            }
            map.put("waybills", waybills2);
            map.put("page", page);
        } catch (Exception e) {
            LOGGER.error("select cwaybill no grab list error : {}.", e);
            throw new BusinessException("查询运单待接单列表异常");
        }
        return map;
    }

    /**
     * @param page
     * @return
     * @Title: getNoGrabListByPage
     * @Description: 查询待接单运单列表
     * @return: Map<String,Object>
     */
    @Override
    public Map<String, Object> getNoGrabListByPage(PageVo page, Boolean isVeneer) {
        LOGGER.info("OrderServiceImpl.getBeQuotedListByPage param : {}", page);
        try {
            List<Integer> statusList = new ArrayList<Integer>();
            statusList.add(WaybillStatusEnum.WAITBID.getValue());
            return this.getCWaybillList(page, statusList, isVeneer);
        } catch (Exception e) {
            LOGGER.error("OrderServiceImpl.getBeQuotedListByPage error : {}", e);
            throw new BusinessException("查询待接单列表异常");
        }
    }

    /**
     * Gets no grab list by page.
     * @param page
     * @return
     */
    @Override
    public Map<String, Object> getNoGrabListByPage(PageVo page){
        LOGGER.info("OrderServiceImpl.getBeQuotedListByPage param : {}", page);
        try {
            List<Integer> statusList = new ArrayList<Integer>();
            statusList.add(WaybillStatusEnum.WAITBID.getValue());
            return this.getCWaybillList(page, statusList);
        } catch (Exception e) {
            LOGGER.error("OrderServiceImpl.getBeQuotedListByPage error : {}", e);
            throw new BusinessException("查询待接单列表异常");
        }
    }

    /**
     * @param page
     * @return
     * @Title: getDoneList
     * @Description: 已完成
     * @return: Result<Map<String,Object>>
     */
    @Override
    public Map<String, Object> getDoneListByPage(PageVo page, Boolean isVeneer) {
        LOGGER.info("OrderServiceImpl.getDoneListByPage param : {}", page);
        try {
            List<Integer> statusList = new ArrayList<Integer>();
            statusList.add(WaybillStatusEnum.DONE.getValue());
            return this.getCWaybillList(page, statusList, isVeneer);
        } catch (Exception e) {
            LOGGER.error("OrderServiceImpl.getDoneListByPage error : {}", e);
            throw new BusinessException("查询已完成列表异常");
        }
    }

    @Override
    public Map<String, Object> getDoneListByPage(PageVo page) {
        LOGGER.info("OrderServiceImpl.getDoneListByPage param : {}", page);
        try {
            List<Integer> statusList = new ArrayList<Integer>();
            statusList.add(WaybillStatusEnum.DONE.getValue());
            return this.getCWaybillList(page, statusList);
        } catch (Exception e) {
            LOGGER.error("OrderServiceImpl.getDoneListByPage error : {}", e);
            throw new BusinessException("查询已完成列表异常");
        }
    }

    /**
     * @param page
     * @return
     * @Title: getAlreadyGrabListByPage
     * @Description: 查询已接单运单列表 === 执行中
     * @return: Map<String,Object>
     */
    @Override
    public Map<String, Object> getAlreadyGrabListByPage(PageVo page, Boolean isVeneer) {
        LOGGER.info("select stan getAlreadyGrabListByPage params page : {}.", page);
        try {
            List<Integer> statusList = new ArrayList<Integer>();
            statusList.add(WaybillStatusEnum.ALREADYBID.getValue());
            statusList.add(WaybillStatusEnum.WAITEXTRACTED.getValue());
            statusList.add(WaybillStatusEnum.EXTRACTED.getValue());
            statusList.add(WaybillStatusEnum.WAITSTART.getValue());
            statusList.add(WaybillStatusEnum.WAITCOMPLETE.getValue());
            statusList.add(WaybillStatusEnum.COMPLETED.getValue());

            return this.getCWaybillList(page, statusList, isVeneer);
        } catch (Exception e) {
            LOGGER.error("select stan getAlreadyGrabListByPage params page : {}, error : {}.", page, e);
            throw new BusinessException("查询执行中运单列表异常");
        }
    }

    /**
     * Gets already grab list by page.
     * @param page
     * @return
     */
    @Override
    public Map<String, Object> getAlreadyGrabListByPage(PageVo page){
        LOGGER.info("select stan getAlreadyGrabListByPage params page : {}.", page);
        try {
            List<Integer> statusList = new ArrayList<Integer>();
            statusList.add(WaybillStatusEnum.ALREADYBID.getValue());
            statusList.add(WaybillStatusEnum.WAITEXTRACTED.getValue());
            statusList.add(WaybillStatusEnum.EXTRACTED.getValue());
            statusList.add(WaybillStatusEnum.WAITSTART.getValue());
            statusList.add(WaybillStatusEnum.WAITCOMPLETE.getValue());
            statusList.add(WaybillStatusEnum.COMPLETED.getValue());

            return this.getCWaybillList(page, statusList);
        } catch (Exception e) {
            LOGGER.error("select stan getAlreadyGrabListByPage params page : {}, error : {}.", page, e);
            throw new BusinessException("查询执行中运单列表异常");
        }
    }

    /**
     * @param id       运单id
     * @param driverId 实际承运人（司机）id
     * @return
     * @Title: grabOne 我要接单
     * @Description: 更新运单的承运人
     * @return: Long 运单id
     */
    @Override
    public Long grabOne(Long id, Long driverId) throws Exception {
        LOGGER.info("user grabOne params id : {}, driverId : {}.", id, driverId);
        if (id == null || id == 0) {
            LOGGER.error("id is null");
            throw new BusinessException("运单id不能为空！");
        }

        // 获取用户信息判断用户是否上线
        UserShowVo user = this.getUserService().getCurrentUser();
        if (UserTypeEnum.COMPANY.getValue() != user.getUserType()) {
            if (UserStatusEnum.F.getValue() == user.getUserStatus()) {
                LOGGER.info("user status is false");
                throw new BusinessException("100", "用户未上线！");
            }
            // 查询用户车辆信息是否验证
            this.getDriverCertInfoService().verifyTheCurrentUservehicleInformationAudit(user.getId(), null);

            //查询用户执行中（未完成）的运单
            List<CWaybillVeneerVo> waybills = cWaybillVeneerService.getExecutionList(null);
            if (CollectionUtils.isNotEmpty(waybills)) {
                LOGGER.info("grabOne waybills is not empty");
                throw new BusinessException("用户有执行中订单！");
            }
        }

        /** if (driverId == null || driverId == 0) {
         // 查询用户车辆信息是否验证
         this.getDriverCertInfoService().verifyTheCurrentUservehicleInformationAudit(user.getId());
         driverId = user.getId();
         } else {
         // 查询用户车辆信息是否验证
         this.getDriverCertInfoService().verifyTheCurrentUservehicleInformationAudit(driverId);
         } */

        String redisKey = null;
        String redisValue = null;
        try {
            redisKey = REDIS_LOCK_WAYBILL_GRAB_PRE + id;
            // 分布锁 多人同时接单
            String lockValue = redisCacheManager.tryLock(redisKey, 5);
            if (StringUtils.isNotEmpty(lockValue)) {
                LOGGER.info("运单:" + id + "获取分布锁成功,继续执行接单流程.");
                redisValue = lockValue;
            } else {
                LOGGER.info("运单:" + id + "获取分布锁失败,已有人接单, 返回.");
                throw new BusinessException("255", "手气太差了，运单已被抢！继续加油哟！");
            }

            // 查询发布状态的运单
            CWaybillExample waybillExample = new CWaybillExample();
            waybillExample.createCriteria().andIdEqualTo(id).andWaybillTypeEqualTo(WaybillTypeEnum.BIDSELF.getValue());
            List<CWaybill> waybills = this.getCWaybillMapper().selectByExample(waybillExample);
            if (CollectionUtils.isEmpty(waybills)) {
                LOGGER.error("waybills is empty");
                throw new BusinessException("获取运单信息失败！");
            }
            CWaybill waybill = waybills.get(0);
            if (waybill.getStatus() != WaybillStatusEnum.WAITBID.getValue()) {
                LOGGER.error("cwaybill status is not published");
                throw new BusinessException("255", "手气太差了，运单已被抢！继续加油哟！");
            }

            Long userId = user.getId();
            // 更新运单状态
            waybill.setStatus(WaybillStatusEnum.ALREADYBID.getValue());
            waybill.setBidderId(userId);
            waybill.setBidderType(user.getUserType());
            if (user.getUserType() == UserTypeEnum.DRIVER.getValue()) {
                waybill.setStatus(WaybillStatusEnum.WAITEXTRACTED.getValue());
                waybill.setActDriver(userId);
            }
            this.getCWaybillMapper().updateByPrimaryKeySelective(waybill);

            // 添加联系人 信息
            this.addContants(userId, waybill.getId());

            // 修改客户订单状态
            CWaybillDetailExample detailExample = new CWaybillDetailExample();
            detailExample.createCriteria().andWaybillIdEqualTo(waybill.getId());
            List<CWaybillDetail> details = this.getCWaybillDetailMapper().selectByExample(detailExample);
            List<Long> serviceOrderIdList = new ArrayList<>();
            for (CWaybillDetail cWaybillDetail : details) {
                Long serviceOrderId = cWaybillDetail.getServiceOrderId();
                if (cWaybillDetail.getServiceDispatchTimes() == 1) {
                    SServiceOrder sServiceOrder = new SServiceOrder();
                    sServiceOrder.setId(serviceOrderId);
                    sServiceOrder.setStatus(SServiceOrderStatusEnum.WAIT_EXTRACT.getValue());
                    this.getSServiceOrderMapper().updateByPrimaryKeySelective(sServiceOrder);

                    // 提车安排通知
                    serviceOrderIdList.add(serviceOrderId);
                }

                // 保存接单记录 每个运单明细增加一条
                // 保存接单记录
                Long bidId = this.getWaybillBidService().addWayBillBid(serviceOrderId, waybill.getId(), userId, true);
                LOGGER.info("接单记录bidId : {}.", bidId);

                // 修改客户订单状态 添加日志
                this.getSOrderService().updateOrderStatusBySid(serviceOrderId);
            }

            // 提车安排通知
            this.sendExtractMessage(serviceOrderIdList, userId);

            return waybill.getId();
        } catch (Exception e) {
            LOGGER.error("user grabOne cwaybill error : {}.", e);
            throw new BusinessException("该运单已被接单");
        } finally {
            redisCacheManager.releaseLock(redisKey, redisValue);
        }
    }

    // 提车安排通知
    @Override
    public void sendExtractMessage(List<Long> serviceOrderIdList, Long userId) {
        LOGGER.info("dirver grab one order sendExtractMessage params serviceOrderIdList : {}, userId : {}.", serviceOrderIdList, userId);
        try {
            Map<Long, List<Long>> map = new HashMap<>();
            Boolean isVeneer = false;
            LOGGER.info("sendExtractMessage params serviceOrderIdList: {}, userId : {}", serviceOrderIdList, userId);
            for (Long sId : serviceOrderIdList) {
                LOGGER.info("sendExtractMessage sId: {}", sId);
                SServiceOrder sServiceOrder = this.getSServiceOrderService().selectById(sId);
                LOGGER.info("sendExtractMessage sServiceOrder: {}", sServiceOrder);
                Long customerOrderId = sServiceOrder.getCustomerOrderId();
                LOGGER.info("sendExtractMessage customerOrderId: {}", customerOrderId);
                isVeneer = sServiceOrder.getIsVeneer();
                LOGGER.info("sendExtractMessage isVeneer: {}", isVeneer);
                if (map.keySet().contains(customerOrderId)) {
                    List<Long> list = map.get(customerOrderId);
                    list.add(sId);
                    map.put(customerOrderId, list);
                } else {
                    List<Long> list = new ArrayList<>();
                    list.add(sId);
                    map.put(customerOrderId, list);
                }
                LOGGER.info("sendExtractMessage map: {}", map);
            }

            SUser user = this.getUserService().getById(userId);
            LOGGER.info("sendExtractMessage user: {}, userType: {}", user, user.getUserType());
            if (user.getUserType() == UserTypeEnum.DRIVER.getValue()) {
                CDriverCertinfo driverInfo = this.getTruckInfoService().queryDriverInfoByUserId(userId);
                LOGGER.info("sendExtractMessage driverInfo: {}", driverInfo);
                String phoneDriver = user.getPhone();
                LOGGER.info("sendExtractMessage phoneDriver: {}", phoneDriver);
                Set<Long> keySet = map.keySet();
                LOGGER.info("sendExtractMessage keySet: {}", keySet);
                String tplValue = "";
                long tplId = 0L;
                for (Long long1 : keySet) {
                    SOrder sorder = this.getSOrderService().selectByPrimaryKey(long1);
                    LOGGER.info("sendExtractMessage sorder: {}", sorder);
                    String departAddr = sorder.getDepartCityName();
                    LOGGER.info("sendExtractMessage departAddr: {}", departAddr);
                    String departCounty = sorder.getDepartCountyName();
                    LOGGER.info("sendExtractMessage departCounty: {}", departCounty);
                    String receiptAddr = sorder.getReceiptCityName();
                    LOGGER.info("sendExtractMessage receiptAddr: {}", receiptAddr);
                    String receiptCounty = sorder.getReceiptCountyName();
                    LOGGER.info("sendExtractMessage receiptCounty: {}", receiptCounty);
                    String orderCode = sorder.getOrderCode();
                    LOGGER.info("sendExtractMessage orderCode: {}", orderCode);
                    String departPerson = user.getRealName();
                    LOGGER.info("sendExtractMessage departPerson: {}", departPerson);
                    String idno = driverInfo.getIdno();
                    LOGGER.info("sendExtractMessage idno: {}", idno);
                    Integer carAmount = map.get(long1).size();
                    LOGGER.info("sendExtractMessage carAmount: {}", carAmount);
                    if (isVeneer) {
                        String time = "1";

                        tplValue = URLEncoder.encode("#phone#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(phoneDriver, JavaSmsApi.getENCODING());
                        tplValue += "&" + URLEncoder.encode("#time#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(time, JavaSmsApi.getENCODING());

                        tplId = JavaSmsApi.VENEER_EXTRACTED_TPL_ID;
                        this.getSendMessageService().sendMessage(tplId, tplValue, sorder.getDepartPhone());
                        LOGGER.info("sendExtractMessage tplId: {}, tplValue: {}, DepartPhone: {}", tplId, tplValue, sorder.getDepartPhone());
                        long timePerson = DateUtils.getDiffHours(sorder.getArriveDate());
                        LOGGER.info("sendExtractMessage timePerson: {}", timePerson);
                        if (timePerson <= 0) {
                            timePerson = 1L;
                        }
                        /** Long tplIdPerson = JavaSmsApi.veneer_jiaocheren_tpl_id;
                         String tplValuePerson = URLEncoder.encode("#phone#",JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(phoneDriver, JavaSmsApi.getENCODING());
                         tplValuePerson += "&" + URLEncoder.encode("#time#",JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(timePerson+"", JavaSmsApi.getENCODING());
                         this.getSendMessageService().sendMessage(tplIdPerson, tplValuePerson, sorder.getReceiptPhone());
                         LOGGER.info("sendExtractMessage tplValuePerson: {}", tplValuePerson); */
                        // 同城业务向下单人消息推送

                        // 查询最后一次登录设备的UUID

                        LOGGER.info("sendExtractMessage serviceOrderId: {}", serviceOrderIdList.get(0));
                        SServiceOrderVehicle serviceOrderVehicle = this.getSServiceOrderVehicleService().selectByServiceOrderId(serviceOrderIdList.get(0) + "");
                        LOGGER.info("sendExtractMessage serviceOrderVehicle: {}", serviceOrderVehicle);
                        BVehicleBrand brand = this.getBVehicleBrandService().selectById(serviceOrderVehicle.getBrandId());
                        LOGGER.info("sendExtractMessage brand: {}", brand);
                        BVehicle vehicle = this.getBVehicleService().selctById(serviceOrderVehicle.getVehicleId());
                        LOGGER.info("sendExtractMessage vehicle: {}", vehicle);

                        SUserDevicesExample example = new SUserDevicesExample();
                        example.setOrderByClause("id desc");
                        example.createCriteria().andUserIdEqualTo(sorder.getUserId());
                        LOGGER.info("sorder.getUserId(): {}", sorder.getUserId());
                        List<SUserDevices> sUserDevices = this.getSUserDevicesMapper().selectByExample(example);
                        LOGGER.info("sUserDevices size: {}", sUserDevices.size());
                        if (CollectionUtils.isNotEmpty(sUserDevices)) {
                            SUserDevices devices = sUserDevices.get(0);
                            LOGGER.info("SUserDevices: {}", devices);
                            List<String> aliases = new ArrayList<String>();
                            aliases.add(devices.getUuid().replaceAll("-", "").replaceAll("_", ""));
                            LOGGER.info("aliases: {}", devices.getUuid().replaceAll("-", "").replaceAll("_", ""));
                            // 推送消息
                            String msg = "尊敬的客户，" + "从" + departCounty + "至" + receiptCounty + "，" + brand.getBrandName() + vehicle.getVehicleName()
                                    + "已接单，司机正前往提车，预计" + time + "小时内到达，司机联系电话" + phoneDriver + "，请通知提车人做好发车准备！";
                            LOGGER.info("msg: {}, devices: {}", msg, devices.getUuid());
                            this.getJPushService().sendMsgStanCityByAliases(aliases, msg, "2");
                        }


                    } else {
                        tplValue = URLEncoder.encode("#departAddr#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(departAddr, JavaSmsApi.getENCODING());
                        tplValue += "&" + URLEncoder.encode("#receiptAddr#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(receiptAddr, JavaSmsApi.getENCODING());
                        tplValue += "&" + URLEncoder.encode("#orderCode#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(orderCode, JavaSmsApi.getENCODING());
                        tplValue += "&" + URLEncoder.encode("#departPerson#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(departPerson, JavaSmsApi.getENCODING());
                        tplValue += "&" + URLEncoder.encode("#idno#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(idno, JavaSmsApi.getENCODING());
                        tplValue += "&" + URLEncoder.encode("#phone#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(phoneDriver, JavaSmsApi.getENCODING());
                        tplValue += "&" + URLEncoder.encode("#carAmount#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(carAmount + "", JavaSmsApi.getENCODING());

                        tplId = JavaSmsApi.EXTRACTED_TPL_ID;
                        String phone = null;
                        Long userId2 = sorder.getUserId();
                        SUser userOrder = this.getUserService().selectByPrimaryKey(userId2);
                        if (null != userOrder) {
                            phone = userOrder.getPhone();
                        }
                        if (null != phone) {
                            this.getSendMessageService().sendMessage(tplId, tplValue, phone);
                        }
                    }
                }
            }
        } catch (Exception e) {
            LOGGER.error("dirver grab one order sendExtractMessage error : {}.", e);
            throw new BusinessException("司机接单,发送提车安排通知异常");
        }
    }

    @Override
    public void sendExtractMessage2(List<Long> serviceOrderIdList, CWaybillContacts contacts) {
        LOGGER.info("stan company grab one order sendExtractMessage params serviceOrderIdList : {}, contacts : {}.", serviceOrderIdList, contacts);
        try {
            Map<Long, List<Long>> map = new HashMap<>();
            for (Long sId : serviceOrderIdList) {
                SServiceOrder sServiceOrder = this.getSServiceOrderService().selectById(sId);
                Long customerOrderId = sServiceOrder.getCustomerOrderId();

                if (map.keySet().contains(customerOrderId)) {
                    List<Long> list = map.get(customerOrderId);
                    list.add(sId);
                    map.put(customerOrderId, list);
                } else {
                    List<Long> list = new ArrayList<>();
                    list.add(sId);
                    map.put(customerOrderId, list);
                }
            }

            Set<Long> keySet = map.keySet();
            for (Long long1 : keySet) {
                SOrder sorder = this.getSOrderService().selectByPrimaryKey(long1);
                // 同城
                if (sorder.getIsVeneer()) {
                    String dateTimeString = DateUtils.getStringFromDate(sorder.getDeliveryDate(), "yyyy-MM-dd").concat(" ").concat(sorder.getDeliveryTime());
                    Date dateTime = DateUtils.StrToDate(dateTimeString, "yyyy-MM-dd HH:mm");
                    if (DateUtils.getDiffHours(dateTime) < -3) {
                        LOGGER.info("Greater than the current time is 3 hours");
                        continue;
                    }
                } else {
                    if (Objects.equals(sorder.getDeliveryDate(), null) || Objects.equals(sorder.getDeliveryDate(), "")) {
                        continue;
                    }
                    int days = DateUtils.daysBetween(sorder.getDeliveryDate(), DateUtils.StrToDate(DateUtils.getCurrentDate()));
                    if (days >= 1) {
                        LOGGER.info("Greater than the current time 1 day");
                        continue;
                    }
                }
                String departAddr = sorder.getDepartCityName();
                String receiptAddr = sorder.getReceiptCityName();
                String orderCode = sorder.getOrderCode();
                String departPerson = contacts.getContact();
                String phoneDriver = contacts.getPhone();
                String idno = HYCUtils.decryptBankCard(contacts.getIdno());
                Integer carAmount = map.get(long1).size();

                String tplValue = URLEncoder.encode("#departAddr#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(departAddr, JavaSmsApi.getENCODING());
                tplValue += "&" + URLEncoder.encode("#receiptAddr#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(receiptAddr, JavaSmsApi.getENCODING());
                tplValue += "&" + URLEncoder.encode("#orderCode#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(orderCode, JavaSmsApi.getENCODING());
                tplValue += "&" + URLEncoder.encode("#departPerson#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(departPerson, JavaSmsApi.getENCODING());
                tplValue += "&" + URLEncoder.encode("#idno#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(idno, JavaSmsApi.getENCODING());
                tplValue += "&" + URLEncoder.encode("#phone#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(phoneDriver, JavaSmsApi.getENCODING());
                tplValue += "&" + URLEncoder.encode("#carAmount#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(carAmount + "", JavaSmsApi.getENCODING());

                long tplId = JavaSmsApi.EXTRACTED_TPL_ID;
                // String phone = sorder.getDepartPhone();
                String phone = null;
                Long userId = sorder.getUserId();
                SUser userOrder = this.getUserService().selectByPrimaryKey(userId);
                if (null != userOrder) {
                    phone = userOrder.getPhone();
                }
                if (null != phone) {
                    this.getSendMessageService().sendMessage(tplId, tplValue, phone);
                }
                // 给发车联系人发送短信
                if (!Objects.equals(sorder.getDepartPhone(), null) && !Objects.equals(sorder.getDepartPhone(), "")) {
                    String departPhone = sorder.getDepartPhone().replaceAll("-", "");
                    this.getSendMessageService().sendMessage(tplId, tplValue, departPhone);
                }
            }
        } catch (Exception e) {
            LOGGER.error("stan compaby grab one order sendExtractMessage error : {}.", e);
            throw new BusinessException("安排司机提车,发送提车安排通知异常");
        }
    }

    @Override
    public Long updateStatus(Long id, int status, int sStatus, UserVo user) {
        LOGGER.info("updateStatus params : {}, {}, {}, {}", id, status, sStatus, user);
        if (id == null) {
            LOGGER.error("id is null");
            throw new BusinessException("运单id不能为空！");
        }
        if (0 == status) {
            LOGGER.error("status is 0");
            throw new BusinessException("状态不能为0！");
        }
        try {
            CWaybill waybill = new CWaybill();
            waybill.setId(id);
            waybill.setStatus(status);
            this.getCWaybillMapper().updateByPrimaryKeySelective(waybill);

            // 添加运单状态变更日志
            CWaybillStatusLog log = new CWaybillStatusLog();
            log.setUpdateTime(new Date());
            log.setCreatTime(new Date());
            log.setCategory(StatusCategoryEnum.PROCESS.getValue());
            log.setComment("司机上传照片修改运单状态");
            log.setUserId(user.getId());
            log.setUserName(user.getUsername());
            log.setWaybillId(id);
            log.setStatus(status);
            this.getCWaybillStatusLogService().addCWaybillStatusLog(log);

            // 更新订单状态
            // this.getSOrderService().updateStatusForWaybill(waybill.getOrderId(), status);
            // 更新服务订单状态
            if (sStatus != 0) {
                CWaybillDetailExample detailExample = new CWaybillDetailExample();
                detailExample.createCriteria().andWaybillIdEqualTo(id);
                List<CWaybillDetail> details = this.getCWaybillDetailMapper().selectByExample(detailExample);
                for (CWaybillDetail cWaybillDetail : details) {
                    SServiceOrder sServiceOrder = new SServiceOrder();
                    sServiceOrder.setId(cWaybillDetail.getServiceOrderId());
                    sServiceOrder.setStatus(sStatus);
                    this.getSServiceOrderMapper().updateByPrimaryKeySelective(sServiceOrder);

                    SServiceOrderStatusLog serviceOrderStatusLog = new SServiceOrderStatusLog();
                    serviceOrderStatusLog.setCreateTime(new Date());
                    serviceOrderStatusLog.setServiceOrderId(cWaybillDetail.getServiceOrderId());
                    serviceOrderStatusLog.setStatus(sStatus);
                    serviceOrderStatusLog.setUserId(user.getId());
                    serviceOrderStatusLog.setUserName(user.getUsername());
                    this.getSServiceOrderStatusLogService().addLog(serviceOrderStatusLog);

                    if (cWaybillDetail.getServiceDispatchTimes() == 1) {
                        SServiceOrderTrail serviceOrderTrail = new SServiceOrderTrail();
                        serviceOrderTrail.setCreateTime(new Date());
                        serviceOrderTrail.setServiceOrderId(cWaybillDetail.getServiceOrderId());
                        serviceOrderTrail.setType(SServiceOrderTrailTypeEnum.SERVICE_ORDER_STATUS.getValue());
                        serviceOrderTrail.setStatus(sStatus);
                        serviceOrderTrail.setInfo(SServiceOrderStatusEnum.getByValue(sStatus).getText());
                        this.getSServiceOrderTrailMapper().insertSelective(serviceOrderTrail);
                    }
                }
            }
            return waybill.getId();
        } catch (Exception e) {
            LOGGER.error("udpate cwaybill status sservice order status error : {}.", e);
            throw new BusinessException("更新运单状态异常");
        }
    }

    @Override
    public Long updateStatusForOrder(Long orderId, int status) {
        LOGGER.info("updateStatusForOrder params : {}, {}", orderId, status);
        if (orderId == null || orderId == 0) {
            LOGGER.error("orderId is null");
            throw new BusinessException("订单id不能为空！");
        }

        CWaybillExample example = new CWaybillExample();
        example.createCriteria().andOrderIdEqualTo(orderId);
        List<CWaybill> waybills = this.getCWaybillMapper().selectByExample(example);
        if (CollectionUtils.isEmpty(waybills)) {
            LOGGER.error("waybills is empty");
            throw new BusinessException("获取运单信息失败！");
        }
        CWaybill waybill = waybills.get(0);
        waybill.setStatus(status);
        this.getCWaybillMapper().updateByPrimaryKeySelective(waybill);

        return waybill.getId();
    }

    @Override
    public Map<String, Object> getUndrawnListByPage(PageVo page) throws Exception {
        LOGGER.info("getUndrawnListByPage params : {}", page);
        Map<String, Object> map = new HashMap<>();
        Map<String, Object> paramsMap = new HashMap<>();
        List<Integer> status = new ArrayList<>();
        status.add(COrderStatusEnum.IN_TRANSIT.getValue());
        paramsMap.put("status", status);
        paramsMap.put("userId", this.getUserService().getCurrentUserVo().getId());
        page.setTotalRecord(this.getSWaybillViewMapper().countByConditions(paramsMap));
        String orderByClause = StringUtils.isNotBlank(page.getOrder()) == true ? page.getOrder()
                : " s.update_time DESC ";
        paramsMap.put("limitStart", page.getStartIndex());
        paramsMap.put("limitEnd", page.getPageSize());
        paramsMap.put("orderByClause", orderByClause);
        List<WaybillNewVo> waybills = this.getSWaybillViewMapper().selectByConditions(paramsMap);
        if (CollectionUtils.isNotEmpty(waybills)) {
            for (int i = waybills.size() - 1; i >= 0; i--) {
                WaybillNewVo vo = waybills.get(i);
                if (vo != null) {
                    vo.setStatusText(SServiceOrderStatusEnum.getByValue(vo.getStatus()).getText());
                    vo.setBidderTypeText(GrabWaybillTypeEnum.getByValue(vo.getBidderType()).getText());
                }
            }
        }
        map.put("waybills", waybills);
        map.put("page", page);
        return map;
    }

    @Override
    public Map<String, Object> getNoDeliveryListByPage(PageVo page) throws Exception {
        LOGGER.info("getNoDeliveryListByPage params : {}", page);
        Map<String, Object> map = new HashMap<>();
        Map<String, Object> paramsMap = new HashMap<>();
        List<Integer> status = new ArrayList<>();
        // status.add(COrderStatusEnum.INTRANSIT.getValue());
        paramsMap.put("status", status);
        paramsMap.put("userId", this.getUserService().getCurrentUserVo().getId());
        page.setTotalRecord(this.getSWaybillViewMapper().countByConditions(paramsMap));
        String orderByClause = StringUtils.isNotBlank(page.getOrder()) == true ? page.getOrder()
                : " s.update_time DESC ";
        paramsMap.put("limitStart", page.getStartIndex());
        paramsMap.put("limitEnd", page.getPageSize());
        paramsMap.put("orderByClause", orderByClause);
        List<WaybillNewVo> waybills = this.getSWaybillViewMapper().selectByConditions(paramsMap);
        if (CollectionUtils.isNotEmpty(waybills)) {
            for (int i = waybills.size() - 1; i >= 0; i--) {
                WaybillNewVo vo = waybills.get(i);
                if (vo != null) {
                    vo.setStatusText(SServiceOrderStatusEnum.getByValue(vo.getStatus()).getText());
                    vo.setBidderTypeText(GrabWaybillTypeEnum.getByValue(vo.getBidderType()).getText());
                }
            }
        }
        map.put("waybills", waybills);
        map.put("page", page);
        return map;
    }

    /**
     * @param id
     * @param attachs
     * @return
     * @Title: confirmExtract
     * @Description: 上传提车照片 待提车
     * @return: Result<Integer>
     */
    @Override
    public Long confirmSend(Long id, String attachs, SysAdminUser adminUser) throws Exception {
        LOGGER.info("confirmSend params : {}, {}", id, attachs);
        // 查询可发车状态的运单
        CWaybillExample example = new CWaybillExample();
        // status.add(COrderStatusEnum.WAITEXTRACTED.getValue());
        // status.add(COrderStatusEnum.EXTRACTED.getValue());
        example.createCriteria().andIdEqualTo(id); // .andStatusIn(status);
        List<CWaybill> waybills = this.getCWaybillMapper().selectByExample(example);
        if (CollectionUtils.isEmpty(waybills)) {
            LOGGER.error("waybills is empty");
            throw new BusinessException("获取运单信息失败！");
        }
        CWaybill waybill = waybills.get(0);

        // 当前用户
        UserVo user = null;
        if (adminUser == null) {
            user = this.getUserService().getCurrentUserVo();
        }
        // 保存附件
        List<AttachForm> objs = JSONArray.parseArray(attachs, AttachForm.class);
        if (CollectionUtils.isNotEmpty(objs)) {
            AttachForm af;
            CWaybillAttach attach = new CWaybillAttach();
            attach.setWaybillId(id);
            if (null != user) {
                attach.setUserId(user.getId());
                attach.setUserName(user.getUsername());
            } else {
                user = new UserVo(adminUser.getId(), adminUser.getUsername(), adminUser.getPassword(), "", true, 0);
                attach.setUserId(adminUser.getId());
                attach.setUserName(adminUser.getUsername());
            }
            attach.setCategory(AttachCategoryEnumWaybill.RECEIPT.getValue());// 提车照片
            for (int i = 0; i < objs.size(); i++) {
                af = objs.get(i);
                attach.setPicKey(af.getImage());
                AttachTypeEnum typeEnum = AttachTypeEnum.getByValue(af.getType());
                if (typeEnum == null) {
                    LOGGER.error("typeEnum is null");
                    throw new BusinessException("图片类型错误!");
                }
                attach.setType(typeEnum.getValue());

                // 照片去重
                CWaybillAttachExample attachExample = new CWaybillAttachExample();
                attachExample.createCriteria().andWaybillIdEqualTo(id).andCategoryEqualTo(AttachCategoryEnumWaybill.RECEIPT.getValue()).andTypeEqualTo(typeEnum.getValue());
                List<CWaybillAttach> attachlist = this.getCWaybillAttachMapper().selectByExample(attachExample);
                if (Collections.isEmpty(attachlist)) {
                    this.getCWaybillAttachMapper().insertSelective(attach);
                } else {
                    Long oldId = attachlist.get(0).getId();
                    attach.setId(oldId);
                    this.getCWaybillAttachMapper().updateByPrimaryKeySelective(attach);
                }
            }
        }

        // 发车推送通知
        /** SOrder order = this.getSOrderMapper().selectByPrimaryKey(waybill.getOrderId());
         String msg = "您的订单" + order.getOrderCode() + "，" + order.getDepartCityName() + "发往" + order.getReceiptCityName()
         + " 已发车，请您做好接车准备！";
         this.getPushService().notifyKyleUser(order.getUserId(), msg); */
        // return this.updateStatus(waybill.getId(),
        // COrderStatusEnum.ALREADYSTART.getValue());
        return this.updateStatus(waybill.getId(), WaybillStatusEnum.EXTRACTED.getValue(), 0, user);
    }

    /**
     * @param id
     * @param attachs
     * @param adminUser
     * @return
     * @Title: confirmDliver
     * @Description: 确定交车 上传交车照片 已交车
     * @return: Result<Integer>
     */
    @Override
    public Long confirmDliver(Long id, String attachs, SysAdminUser adminUser) {
        LOGGER.info("upload jiaoche piccture params id : {}, attachs : {}.", id, attachs);
        try {
            // 查询可交车状态的运单
            CWaybillExample example = new CWaybillExample();
            example.createCriteria().andIdEqualTo(id); //.andStatusEqualTo(COrderStatusEnum.INTRANSIT.getValue());
            List<CWaybill> waybills = this.getCWaybillMapper().selectByExample(example);
            if (CollectionUtils.isEmpty(waybills)) {
                LOGGER.error("waybills is empty");
                throw new BusinessException("获取运单信息失败！");
            }
            CWaybill waybill = waybills.get(0);

            // 当前用户
            UserVo user = null;
            if (adminUser == null) {
                user = this.getUserService().getCurrentUserVo();
            }

            // 保存附件
            List<AttachForm> objs = JSONArray.parseArray(attachs, AttachForm.class);
            if (CollectionUtils.isNotEmpty(objs)) {
                AttachForm af;
                CWaybillAttach attach = new CWaybillAttach();
                attach.setWaybillId(id);
                if (null != user) {
                    attach.setUserId(user.getId());
                    attach.setUserName(user.getUsername());
                } else {
                    user = new UserVo(adminUser.getId(), adminUser.getUsername(), adminUser.getPassword(), "", true, 0);
                    attach.setUserId(adminUser.getId());
                    attach.setUserName(adminUser.getUsername());
                }
                attach.setCategory(AttachCategoryEnumWaybill.DELIVER.getValue());// 交车照片
                for (int i = 0; i < objs.size(); i++) {
                    af = objs.get(i);
                    attach.setPicKey(af.getImage());
                    AttachTypeEnum typeEnum = AttachTypeEnum.getByValue(af.getType());
                    if (typeEnum == null) {
                        LOGGER.error("typeEnum is null");
                        throw new BusinessException("图片类型错误!");
                    }
                    attach.setType(typeEnum.getValue());
                    // 照片去重
                    CWaybillAttachExample attachExample = new CWaybillAttachExample();
                    attachExample.createCriteria().andWaybillIdEqualTo(id).andCategoryEqualTo(AttachCategoryEnumWaybill.DELIVER.getValue()).andTypeEqualTo(typeEnum.getValue());
                    List<CWaybillAttach> attachlist = this.getCWaybillAttachMapper().selectByExample(attachExample);
                    if (Collections.isEmpty(attachlist)) {
                        this.getCWaybillAttachMapper().insertSelective(attach);
                    } else {
                        Long oldId = attachlist.get(0).getId();
                        attach.setId(oldId);
                        this.getCWaybillAttachMapper().updateByPrimaryKeySelective(attach);
                    }
                }
            }
            // 交车推送通知
            /** SOrder order = this.getSOrderMapper().selectByPrimaryKey(waybill.getOrderId());
             String msg = "您的订单" + order.getOrderCode() + "，" + order.getDepartCityName() + "发往" + order.getReceiptCityName()
             + " 已交车，感谢您使用慧运车！ ";
             this.getPushService().notifyKyleUser(order.getUserId(), msg); */
            return this.updateStatus(waybill.getId(), WaybillStatusEnum.COMPLETED.getValue(), 0, user);
        } catch (Exception e) {
            LOGGER.info("upload jiaoche piccture params id : {}, attachs : {}, error ; {}.", id, attachs, e);
            throw new BusinessException("上传交车照片异常");
        }
    }

    @Override
    public List<CWaybill> selectByUseridAndStatus(Long userId, List<Integer> statusList) {
        LOGGER.info("selectByUseridAndStatus params : {}, {}", userId, statusList);
        // 查询可交车状态的运单
        CWaybillExample example = new CWaybillExample();
        example.createCriteria().andActDriverEqualTo(userId).andStatusIn(statusList);
        List<CWaybill> waybills = this.getCWaybillMapper().selectByExample(example);
        return waybills;
    }

    @Override
    public CWaybill getWayBillById(Long id) {
        LOGGER.info("getWayBillById param : {}", id);
        return this.getCWaybillMapper().selectByPrimaryKey(id);
    }

    @Override
    public Map<String, Object> getAllListByPage(PageVo page) throws Exception {
        LOGGER.info("getAllListByPage params : {}", page);
        Map<String, Object> map = new HashMap<>();
        Map<String, Object> paramsMap = new HashMap<>();
        List<Integer> status = new ArrayList<>();
        // status.add(COrderStatusEnum.CONFIRMED.getValue());
        // status.add(COrderStatusEnum.WAITEXTRACTED.getValue());
        // status.add(COrderStatusEnum.EXTRACTED.getValue());
        // status.add(COrderStatusEnum.ALREADYSTART.getValue());
        // status.add(COrderStatusEnum.INTRANSIT.getValue());
        // status.add(COrderStatusEnum.COMPLETED.getValue());
        // status.add(COrderStatusEnum.DONE.getValue());
        paramsMap.put("status", status);
        paramsMap.put("userId", this.getUserService().getCurrentUserVo().getId());
        page.setTotalRecord(this.getSWaybillViewMapper().countByConditions(paramsMap));
        String orderByClause = StringUtils.isNotBlank(page.getOrder()) == true ? page.getOrder()
                : " s.update_time DESC ";
        paramsMap.put("limitStart", page.getStartIndex());
        paramsMap.put("limitEnd", page.getPageSize());
        paramsMap.put("orderByClause", orderByClause);
        List<WaybillNewVo> waybills = this.getSWaybillViewMapper().selectByConditions(paramsMap);
        if (CollectionUtils.isNotEmpty(waybills)) {
            for (int i = waybills.size() - 1; i >= 0; i--) {
                WaybillNewVo vo = waybills.get(i);
                if (vo != null) {
                    vo.setStatusText(SServiceOrderStatusEnum.getByValue(vo.getStatus()).getText());
                    vo.setBidderTypeText(GrabWaybillTypeEnum.getByValue(vo.getBidderType()).getText());
                }
            }
        }
        map.put("waybills", waybills);
        map.put("page", page);
        return map;
    }

    @Override
    public CWaybill getByOrderId(Long orderId) {
        LOGGER.info("getByOrderId param : {}", orderId);
        if (null == orderId) {
            LOGGER.error("getByOrderId orderId must not be null");
            throw new BusinessException("订单id不能为空！");
        }
        CWaybillExample example = new CWaybillExample();
        example.createCriteria().andOrderIdEqualTo(orderId);
        List<CWaybill> list = this.getCWaybillMapper().selectByExample(example);
        if (CollectionUtils.isEmpty(list)) {
            LOGGER.error("getByOrderId list must not be empty");
            throw new BusinessException("获取运单信息失败！");
        }
        return list.get(0);
    }

    public CWaybillDetailsVo buildInfo(Long serviceOrderId, Long bidderId, Integer waybillType) {
        LOGGER.info("create veener waybill params serviceOrderId : {}.", serviceOrderId);
        SServiceOrder sServiceOrder = this.getSServiceOrderService().selectById(serviceOrderId);
        if (null == sServiceOrder) {
            LOGGER.info("create veener waybill params serviceOrderId : {}, serviceorder is null.", serviceOrderId);
            throw new BusinessException("服务订单不存在");
        }

        if (sServiceOrder.getDispatchTimes() > 0) {
            throw new BusinessException("该服务订单已被调度，请刷新页面");
        }

        try {
            SServiceOrderAdminVo sServiceOrderAdminVo = this.getSServiceOrderService().getSServiceOrderAdminVoById(serviceOrderId);
            LOGGER.info("create veener waybill params serviceOrderId : {}, sServiceOrderAdminVo : {}.", serviceOrderId, sServiceOrderAdminVo);

            SOrder sOrder = this.getSOrderMapper().selectByPrimaryKey(sServiceOrderAdminVo.getCustomerOrderId());

            CWaybillDetailsVo cWaybillDetailsVo = new CWaybillDetailsVo();
            BeanUtils.copyProperties(sServiceOrderAdminVo, cWaybillDetailsVo);

            Date arriveDate = sServiceOrderAdminVo.getArriveDate();
            String arriveTime = sServiceOrderAdminVo.getArriveTime();

            Date deliveryDate = sServiceOrderAdminVo.getDeliveryDate();
            String deliveryTime = sServiceOrderAdminVo.getDeliveryTime();

            SimpleDateFormat sftime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String sArriveDate = sftime.format(arriveDate).substring(0, 10) + " " + arriveTime + ":00";
            Date unloadTime = sftime.parse(sArriveDate);

            String sDeliveryDate = sftime.format(deliveryDate).substring(0, 10) + " " + deliveryTime + ":00";
            Date loadTime = sftime.parse(sDeliveryDate);

            cWaybillDetailsVo.setLoadTime(loadTime);
            cWaybillDetailsVo.setUnloadTime(unloadTime);
            cWaybillDetailsVo.setShipmentDate(loadTime);
            cWaybillDetailsVo.setArriveDate(unloadTime);

            cWaybillDetailsVo.setWaybillType(waybillType);
            cWaybillDetailsVo.setBidderId(bidderId);

            cWaybillDetailsVo.setDepartDriverPhone(sOrder.getDepartPhone());
            cWaybillDetailsVo.setDepartDriverName(sOrder.getDepartContact());
            cWaybillDetailsVo.setReceiptDriverName(sOrder.getReceiptContact());
            cWaybillDetailsVo.setReceiptDriverPhone(sOrder.getReceiptPhone());

            List<Long> serviceOrderIds = new ArrayList<>();
            serviceOrderIds.add(serviceOrderId);

            BigDecimal cost = this.proposedPrice(cWaybillDetailsVo.getDepartCityCode(), cWaybillDetailsVo.getDepartAddr(), cWaybillDetailsVo.getReceiptCityCode(), cWaybillDetailsVo.getReceiptAddr(), new Date(), 0, serviceOrderIds);
            cWaybillDetailsVo.setCost(cost);

            cWaybillDetailsVo.setSorderIds(Long.toString(serviceOrderId));

            return cWaybillDetailsVo;
        } catch (Exception e) {
            LOGGER.error("create veener waybill params serviceOrderId : {}, error : {}.", serviceOrderId, e);
            throw new BusinessException("查询同城运单异常");
        }
    }

    @Override
    public String saveCWaybillWithUserToRedis(Long cWaybillId, Long userId) {

        LOGGER.info("saveCWaybillWithUserToRedis params : {}", cWaybillId, userId);
        if (null == cWaybillId) {
            LOGGER.error("saveCWaybillWithUserToRedis param cWaybillId must not be null");
            throw new IllegalArgumentException("运单主键不能为空");
        }
        if (null == userId) {
            LOGGER.error("saveCWaybillWithUserToRedis param userId must not be null");
            throw new IllegalArgumentException("用户主键不能为空");
        }

        jedis = HYCUtils.getJedis();
        try {
            String now = DateUtils.getStringFromDate(new Date(), "yyyy-MM-dd HH:mm:ss");
            String info = cWaybillId.toString() + CW_WITH_USER_INFO_CONCAT_SYMBOL + userId.toString() + CW_WITH_USER_INFO_CONCAT_SYMBOL + now;
            System.out.println("==========resource==========" + info);
            jedis.lpush(CW_WITH_USER, info);
        } finally {
            jedis.close();
        }

        return CW_WITH_USER;
    }

//    @Override
//    public Boolean removeCWaybillWithUserFromRedis(Long cWaybillId, Long userId) {
//	    LOGGER.info("removeCWaybillWithUserFromRedis params : {}, {}", cWaybillId, userId);
//        if(null==cWaybillId){
//            LOGGER.error("removeCWaybillWithUserFromRedis param cWaybillId must not be null");
//            throw new IllegalArgumentException("运单主键不能为空");
//        }
//        if(null==userId){
//            LOGGER.error("removeCWaybillWithUserFromRedis param userId must not be null");
//            throw new IllegalArgumentException("用户主键不能为空");
//        }
//
//        jedis = HYCUtils.getJedis();
//        try {
//            TmsQueueApi.setJedis(jedis);
//            Long lengthTem = TmsQueueApi.getQueueLength(CW_WITH_USER);
//            for (long i = 0; i < lengthTem; i++) {
//                String data = TmsQueueApi.getDataByIndex(CW_WITH_USER, i);
//                if (StringUtils.isNotBlank(data)) {
//                    String info = cWaybillId.toString()+":"+userId.toString();
//                    if(data.startsWith(info)){
//                        TmsQueueApi.remove(CW_WITH_USER, data);
//                        return true;
//                    }
//                }
//            }
//        } finally {
//            jedis.close();
//        }
//        return false;
//    }

    @Override
    public List<Long> getCWaybillByUserFromRedis(Long userId) {
        LOGGER.info("getCWaybillByUserFromRedis params : {}", userId);
        if (null == userId) {
            LOGGER.error("getCWaybillByUserFromRedis param userId must not be null");
            throw new IllegalArgumentException("用户主键不能为空");
        }

        jedis = HYCUtils.getJedis();
        try {
            List<Long> cWaybillIds = new ArrayList<>();
            Long lengthTem = jedis.llen(CW_WITH_USER);
            for (long i = 0; i < lengthTem; i++) {
                String data = jedis.lindex(CW_WITH_USER, i);

                if (StringUtils.isNotBlank(data)) {
                    String info = userId.toString();
                    if (data.contains(info)) {
                        cWaybillIds.add(NumberUtils.toLong(data.substring(0, data.indexOf(CW_WITH_USER_INFO_CONCAT_SYMBOL))));
                    }
                }

            }
            return cWaybillIds;
        } finally {
            jedis.close();
        }

    }

    @Override
    public Long getUserByCWaybillFromRedis(Long cWaybillId) {
        LOGGER.info("getUserByCWaybillFromRedis params : {}", cWaybillId);
        if (null == cWaybillId) {
            LOGGER.error("getUserByCWaybillFromRedis param cWaybillId must not be null");
            throw new IllegalArgumentException("运单主键不能为空");
        }

        jedis = HYCUtils.getJedis();
        try {
            Long lengthTem = jedis.llen(CW_WITH_USER);
            for (long i = 0; i < lengthTem; i++) {
                String data = jedis.lindex(CW_WITH_USER, i);

                if (StringUtils.isNotBlank(data)) {
                    String info = cWaybillId.toString();
                    if (data.contains(info)) {
                        String[] strings = data.split(CW_WITH_USER_INFO_CONCAT_SYMBOL);
                        return NumberUtils.toLong(strings[1]);
                    }
                }

            }
        } finally {
            jedis.close();
        }
        return null;
    }

    @Override
    public Boolean isExistInRedis(Long cWaybillId, Long userId, Boolean isRemove) {
        LOGGER.info("isExistInRedis params : {}, {}, {}", cWaybillId, userId, isRemove);
        if (null == cWaybillId) {
            LOGGER.error("isExistInRedis param cWaybillId must not be null");
            throw new IllegalArgumentException("运单主键不能为空");
        }
        if (null == userId) {
            LOGGER.error("isExistInRedis param userId must not be null");
            throw new IllegalArgumentException("用户主键不能为空");
        }
        if (null == isRemove) {
            LOGGER.info("isExistInRedis param isRemove is null, set default value false");
            isRemove = false;
        }

        jedis = HYCUtils.getJedis();
        try {
            Long lengthTem = jedis.llen(CW_WITH_USER);
            for (long i = 0; i < lengthTem; i++) {
                String data = jedis.lindex(CW_WITH_USER, i);
                if (StringUtils.isNotBlank(data)) {
                    String info = cWaybillId.toString() + CW_WITH_USER_INFO_CONCAT_SYMBOL + userId.toString();
                    if (data.startsWith(info)) {
                        if (isRemove) {
                            String removeString = data;
                            if (StringUtils.isBlank(data)) {
                                removeString = jedis.lpop(CW_WITH_USER);
                            }
                            if (StringUtils.isNotBlank(removeString)) {
                                jedis.lrem(CW_WITH_USER, 1L, removeString);
                            }
                        }
                        return true;
                    }
                }
            }
        } finally {
            jedis.close();
        }

        return false;
    }

    @Override
    public List<String> getAllCWaybillWithUserFromRedis() {
        LOGGER.info("getAllCWaybillWithUserFromRedis start");

        jedis = HYCUtils.getJedis();
        try {
            List<String> list = new ArrayList<>();
            Long lengthTem = jedis.llen(CW_WITH_USER);
            for (long i = 0; i < lengthTem; i++) {
                String data = jedis.lindex(CW_WITH_USER, i);
                if (StringUtils.isNotBlank(data)) {
                    list.add(data);
                }
            }

            return list;
        } finally {
            jedis.close();
        }
    }

    /**
     * 创建运单
     */
    @Override
    public Result<String> createVeneer(Long serviceOrderId, Long bidderId, Integer waybillType, SysAdminUser sysAdminUser) {
        LOGGER.info("create veneer waybill params serviceOrderId : {}, bidderId : {}, waybillType : {}, sysAdminUser : {}.", serviceOrderId, bidderId, waybillType, sysAdminUser);
        Result<String> result = new Result<>(true, "派单/抢单完成");
        try {
            LOGGER.info("create veener waybill params serviceOrderId : {}.", serviceOrderId);
            SServiceOrderAdminVo sServiceOrderAdminVo = this.getSServiceOrderService().getSServiceOrderAdminVoById(serviceOrderId);
            if (null == sServiceOrderAdminVo) {
                LOGGER.info("create veener waybill params serviceOrderId : {}, serviceorder is null.", serviceOrderId);
                throw new BusinessException("服务订单不存在");
            } else if (sServiceOrderAdminVo.getDispatchTimes() > 0) {
                throw new BusinessException("该服务订单已被调度，请刷新页面");
            }
            LOGGER.info("create veener waybill params serviceOrderId : {}, sServiceOrderAdminVo : {}.", serviceOrderId, sServiceOrderAdminVo);

            String departCountyName = sServiceOrderAdminVo.getDepartCountyName();
            String receiptCountyName = sServiceOrderAdminVo.getReceiptCountyName();
            // 写入运单表数据
            CWaybill cWaybill = this.addCWaybill(sServiceOrderAdminVo, waybillType, bidderId);
            if (waybillType == WaybillTypeEnum.ASSIGN.getValue()) {
                // 写入redis
                this.saveCWaybillWithUserToRedis(cWaybill.getId(), bidderId);
                // 给司机推送消息
                this.sendStanCityMessage(serviceOrderId, cWaybill.getWaybillCode(), departCountyName, receiptCountyName, bidderId);
            } else {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                String msgDate = sdf.format(cWaybill.getShipmentDate());
                // 查询所有在线用户
                SUserExample example = new SUserExample();
                example.createCriteria().andUserStatusEqualTo(UserStatusEnum.T.getValue());
                List<SUser> users = this.getSUserMapper().selectByExample(example);
                List<Long> userIds = new ArrayList<Long>();
                List<String> aliases = new ArrayList<String>();
                LOGGER.info("current users : {}", JSONArray.toJSONString(users));
                if (CollectionUtils.isNotEmpty(users)) {
                    for (SUser sUser : users) {
                        userIds.add(sUser.getId());
                    }
                    // 查询所有设备
                    List<SUserDevices> devices = this.getSUserDevicesExtMapper().selectDevicesByUserIds(userIds);
                    LOGGER.info("current devices : {}", JSONArray.toJSONString(devices));
                    if (CollectionUtils.isNotEmpty(devices)) {
                        for (SUserDevices sUserDevices : devices) {
                            aliases.add(sUserDevices.getUuid().replaceAll("-", "").replaceAll("_", ""));
                        }
                    }
                }
                LOGGER.info("current aliases : {}", JSONArray.toJSONString(aliases));
                if (CollectionUtils.isNotEmpty(aliases)) {
                    LOGGER.info("cWaybill.getIsVeneer(): {}", cWaybill.getIsVeneer());
                    // 推送消息
                    if (cWaybill.getIsVeneer()) {
                        String msg = "发现了一条新运单，" + msgDate.substring(5, 7) + "月" + msgDate.substring(8, 10) + "日从" + departCountyName + "至" + receiptCountyName + "的运单";
                        LOGGER.info("msg: {}", msg);
                        this.getJPushService().sendMsgStanCityByAliases(aliases, msg, "1");
                    }
                }
            }

            // 写入运单明细数据
            this.addCWaybillDetail(serviceOrderId, cWaybill);

            // 更新服务订单调度次数
            SServiceOrder sServiceOrder = new SServiceOrder();
            sServiceOrder.setId(serviceOrderId);
            sServiceOrder.setDispatchTimes(1);
            this.getSServiceOrderService().update(sServiceOrder);

            // 写入运单 地址
            this.addCWaybillAddress(sServiceOrderAdminVo, cWaybill);

        } catch (Exception e) {
            LOGGER.info("create veneer waybill params serviceOrderId : {}, bidderId : {}, waybillType : {}, sysAdminUser : {}, error : {}.", serviceOrderId, bidderId, waybillType, sysAdminUser, e);
            throw new BusinessException("同城业务抢单/派单异常");
        }
        return result;
    }

    private void addCWaybillAddress(SServiceOrderAdminVo sServiceOrderAdminVo, CWaybill cWaybill) {

        SOrder sOrder = this.getSOrderMapper().selectByPrimaryKey(sServiceOrderAdminVo.getCustomerOrderId());

        CWaybillAddress cWaybillAddress = new CWaybillAddress();
        String departProvinceName = sServiceOrderAdminVo.getDepartProvinceName();
        String departCityName = sServiceOrderAdminVo.getDepartCityName();
        String receiptProvinceName = sServiceOrderAdminVo.getReceiptProvinceName();
        String receiptCityName = sServiceOrderAdminVo.getReceiptCityName();
        if (StringUtils.isEmpty(receiptCityName)) {
            receiptCityName = receiptProvinceName;
        }
        if (StringUtils.isEmpty(departCityName)) {
            departCityName = departProvinceName;
        }
        cWaybillAddress.setDepartProvinceCode(sServiceOrderAdminVo.getDepartProvinceCode());
        cWaybillAddress.setDepartProvinceName(departProvinceName);
        cWaybillAddress.setDepartCityCode(sServiceOrderAdminVo.getDepartCityCode());
        cWaybillAddress.setDepartCityName(departCityName);
        cWaybillAddress.setDepartCountyCode(sServiceOrderAdminVo.getDepartCountyCode());
        cWaybillAddress.setDepartCountyName(sServiceOrderAdminVo.getDepartCountyName());
        cWaybillAddress.setDepartAddr(sServiceOrderAdminVo.getDepartAddr());
        cWaybillAddress.setDepartContact(sOrder.getDepartContact());
        cWaybillAddress.setDepartPhone(sOrder.getDepartPhone());

        cWaybillAddress.setReceiptProvinceCode(sServiceOrderAdminVo.getReceiptProvinceCode());
        cWaybillAddress.setReceiptProvinceName(receiptProvinceName);
        cWaybillAddress.setReceiptCityCode(sServiceOrderAdminVo.getReceiptCityCode());
        cWaybillAddress.setReceiptCityName(receiptCityName);
        cWaybillAddress.setReceiptCountyCode(sServiceOrderAdminVo.getReceiptCountyCode());
        cWaybillAddress.setReceiptCountyName(sServiceOrderAdminVo.getReceiptCountyName());
        cWaybillAddress.setReceiptAddr(sServiceOrderAdminVo.getReceiptAddr());
        cWaybillAddress.setReceiptContact(sOrder.getReceiptContact());
        cWaybillAddress.setReceiptPhone(sOrder.getReceiptPhone());

        cWaybillAddress.setWaybillId(cWaybill.getId());

        cWaybillAddress.setDistance(sOrder.getDistance());

        cWaybillAddress.setCreateTime(new Date());
        cWaybillAddress.setUpdateTime(new Date());
        this.getCWaybillAddressService().addAddress(cWaybillAddress);
    }

    private void addCWaybillDetail(Long serviceOrderId, CWaybill cWaybill) {
        SServiceOrderVehicle vehicle = this.getSServiceOrderVehicleService().selectByServiceOrderId(serviceOrderId + "");
        Long vehicleId = vehicle.getVehicleId();
        BVehicle bVehicle = this.getBVehicleService().getById(vehicleId);

        Long brandId = bVehicle.getBrandId();
        LOGGER.info("create waybill insert details brandId : {}.", brandId);
        BVehicleBrand bVehicleBrand = this.getBVehicleBrandService().selectById(brandId);

        // 查询服务订单
        SServiceOrder sorder = this.getSServiceOrderService().selectById(serviceOrderId);
        if (sorder == null) {
            LOGGER.info("create cwaybill add cwaybill details sorder is null.");
            throw new BusinessException("创建运单添加运单明细查询服务订单异常");
        }
        CWaybillDetail cWaybillDetail = new CWaybillDetail();
        cWaybillDetail.setActualDepartTime(cWaybill.getLoadTime()); // 实际提车时间
        cWaybillDetail.setActualReceiptTime(cWaybill.getUnloadTime()); // 实际送达时间
        cWaybillDetail.setBrandId(brandId);
        cWaybillDetail.setBrandName(bVehicleBrand.getBrandName());
        cWaybillDetail.setVehicleId(vehicleId);
        cWaybillDetail.setVehicleName(bVehicle.getVehicleName());
        cWaybillDetail.setVin(vehicle.getVin()); // 车架号

        cWaybillDetail.setServiceOrderId(serviceOrderId); // 服务订单id
        cWaybillDetail.setServiceDispatchTimes(sorder.getDispatchTimes() + 1); // 添加服务订单 调度次数
        cWaybillDetail.setWaybillId(cWaybill.getId()); // 运单 id
        cWaybillDetail.setSingleFee(cWaybill.getCost());

        cWaybillDetail.setCreateTime(new Date());
        cWaybillDetail.setUpdateTime(new Date());

        this.getCWaybillDetailMapper().insertSelective(cWaybillDetail);
    }

    private CWaybill addCWaybill(SServiceOrderAdminVo sServiceOrderAdminVo, Integer waybillType, Long bidderId) {
        try {
            CWaybill cWaybill = new CWaybill();
            BeanUtils.copyProperties(sServiceOrderAdminVo, cWaybill);

            Date arriveDate = sServiceOrderAdminVo.getArriveDate();
            String arriveTime = sServiceOrderAdminVo.getArriveTime();

            Date deliveryDate = sServiceOrderAdminVo.getDeliveryDate();
            String deliveryTime = sServiceOrderAdminVo.getDeliveryTime();

            SimpleDateFormat sftime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String sArriveDate = sftime.format(arriveDate).substring(0, 10) + " " + arriveTime + ":00";
            Date unloadTime = sftime.parse(sArriveDate);

            String sDeliveryDate = sftime.format(deliveryDate).substring(0, 10) + " " + deliveryTime + ":00";
            Date loadTime = sftime.parse(sDeliveryDate);

            cWaybill.setLoadTime(loadTime);
            cWaybill.setUnloadTime(unloadTime);
            cWaybill.setShipmentDate(loadTime);
            cWaybill.setArriveDate(unloadTime);

            cWaybill.setWaybillType(waybillType);
            SUser user = this.getUserService().selectByPrimaryKey(bidderId);
            if (null != user) {
                cWaybill.setBidderType(user.getUserType());
            }

            List<Long> serviceIdList = new ArrayList<>();
            serviceIdList.add(sServiceOrderAdminVo.getId());
            BigDecimal cost = this.proposedPrice(sServiceOrderAdminVo.getDepartCityCode(), sServiceOrderAdminVo.getDepartAddr(), sServiceOrderAdminVo.getReceiptCityCode(), sServiceOrderAdminVo.getReceiptAddr(), new Date(), 0, serviceIdList);
            cWaybill.setCost(cost);

            cWaybill.setWaybillCode(UniquenessFlagUnits.generateUniquenessFlag("WB"));
            cWaybill.setPayStatus(WaybillPayStatusEnum.UNPAID.getValue());
            cWaybill.setStatus(WaybillStatusEnum.WAITBID.getValue());

            this.getCWaybillMapper().insertSelective(cWaybill);
            return cWaybill;
        } catch (Exception e) {
            throw new BusinessException("");
        }
    }

    /**
     * 创建运单
     */
    @Override
    public Result<String> create(CWaybillDetailsVo cWaybillDetailsVo, SysAdminUser adminUser) {
        LOGGER.info("create params : {}", cWaybillDetailsVo);
        Result<String> result = new Result<String>(true, "创建运单完成");
        LOGGER.info("create waybill order .");
        try {
            Date currentTime = new Date();
            // 创建运单
            CWaybill cWaybill = new CWaybill();

            result = this.validateParams(cWaybillDetailsVo);
            if (!result.isSuccess()) {
                return result;
            }
            LOGGER.info("cWaybillDetailsVo: {}", cWaybillDetailsVo);
            BeanUtils.copyProperties(cWaybillDetailsVo, cWaybill);

            LOGGER.info("CWaybillServiceImpl.create: {}", cWaybill);

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            String msgDate = sdf.format(cWaybillDetailsVo.getShipmentDate());
            String departCityName = this.getBAreaService().getFullByCode(cWaybillDetailsVo.getDepartCityCode());
            String receiptCityName = this.getBAreaService().getFullByCode(cWaybillDetailsVo.getReceiptCityCode());
            // 生成运单编码
            cWaybill.setWaybillCode(UniquenessFlagUnits.generateUniquenessFlag("WB"));
            LOGGER.info("waybillCode: {}", cWaybill.getWaybillCode());
            // 运单状态 支付状态
            cWaybill.setPayStatus(WaybillPayStatusEnum.UNPAID.getValue());
            LOGGER.info("cWaybill.getWaybillType(): {}", cWaybill.getWaybillType());
            if (cWaybill.getWaybillType() == WaybillTypeEnum.ASSIGN.getValue()) {
                // 指派运单 －－ 需要填写接车和交车联系人为司机
                cWaybill.setStatus(WaybillStatusEnum.ALREADYBID.getValue()); // 已接单
                // 拿到指派人的ID 判断类型是司机还是承运商
                Long bidderId = cWaybillDetailsVo.getBidderId();
                LOGGER.info("cWaybillDetailsVo.getBidderId(): {}", cWaybillDetailsVo.getBidderId());
                Integer driverType = this.getUserService().getById(bidderId).getUserType();
                LOGGER.info("driverType", driverType);
                if (driverType == UserTypeEnum.DRIVER.getValue()) {
                    cWaybillDetailsVo.setBidderType(UserTypeEnum.DRIVER.getValue());
                    cWaybill.setActDriver(bidderId);
                    cWaybill.setBidderType(UserTypeEnum.DRIVER.getValue());
                    cWaybill.setStatus(WaybillStatusEnum.WAITEXTRACTED.getValue()); // 待提车
                    // 查询最后一次登录设备的UUID
                    SUserDevicesExample example = new SUserDevicesExample();
                    example.setOrderByClause("id desc");
                    example.createCriteria().andUserIdEqualTo(bidderId);
                    List<SUserDevices> sUserDevices = this.getSUserDevicesMapper().selectByExample(example);
                    LOGGER.info("sUserDevices size: {}", JSONArray.toJSONString(sUserDevices));
                    if (CollectionUtils.isNotEmpty(sUserDevices)) {
                        SUserDevices devices = sUserDevices.get(0);
                        List<String> aliases = new ArrayList<String>();
                        aliases.add(devices.getUuid().replaceAll("-", "").replaceAll("_", ""));
                        LOGGER.info("aliases: {}", devices.getUuid().replaceAll("-", "").replaceAll("_", ""));
                        LOGGER.info("isVeneer: {}", cWaybill.getIsVeneer());
                        // 推送消息
                        String msg = "您被派发了一条新运单，" + msgDate.substring(5, 7) + "月" + msgDate.substring(8, 10) + "日从" + departCityName + "至" + receiptCityName + "的运单";
                        LOGGER.info("msg: {}, devices: {}", msg, devices.getUuid());
                        this.getJPushService().sendMsgStanByAliases(aliases, msg, "2");
                    }
                } else {
                    cWaybillDetailsVo.setBidderType(UserTypeEnum.COMPANY.getValue());
                    cWaybill.setBidderType(UserTypeEnum.COMPANY.getValue());
                }
            } else if (cWaybill.getWaybillType() == WaybillTypeEnum.BIDSELF.getValue()) {
                // 接单
                cWaybill.setStatus(WaybillStatusEnum.WAITBID.getValue()); // 待接单
                // 查询所有在线用户
                SUserExample example = new SUserExample();
                example.createCriteria().andUserStatusEqualTo(UserStatusEnum.T.getValue());
                List<SUser> users = this.getSUserMapper().selectByExample(example);
                List<Long> userIds = new ArrayList<Long>();
                List<String> aliases = new ArrayList<String>();
                LOGGER.info("current users : {}", JSONArray.toJSONString(users));
                if (CollectionUtils.isNotEmpty(users)) {
                    for (SUser sUser : users) {
                        userIds.add(sUser.getId());
                    }
                    // 查询所有设备
                    List<SUserDevices> devices = this.getSUserDevicesExtMapper().selectDevicesByUserIds(userIds);
                    LOGGER.info("current devices : {}", JSONArray.toJSONString(devices));
                    if (CollectionUtils.isNotEmpty(devices)) {
                        for (SUserDevices sUserDevices : devices) {
                            aliases.add(sUserDevices.getUuid().replaceAll("-", "").replaceAll("_", ""));
                        }
                    }
                }
                LOGGER.info("current aliases : {}", JSONArray.toJSONString(aliases));
                if (CollectionUtils.isNotEmpty(aliases)) {
                    LOGGER.info("cWaybill.getIsVeneer(): {}", cWaybill.getIsVeneer());
                    String msg = "发现了一条新运单，" + msgDate.substring(5, 7) + "月" + msgDate.substring(8, 10) + "日从" + departCityName + "至" + receiptCityName + "的运单";
                    LOGGER.info("msg: {}", msg);
                    this.getJPushService().sendMsgStanByAliases(aliases, msg, "1");
                }
            }

            cWaybill.setCreateTime(currentTime);
            cWaybill.setUpdateTime(currentTime);

            int insertCount = this.getCWaybillMapper().insertSelective(cWaybill);
            LOGGER.info("create waybill order count : {}.", insertCount);

            if (cWaybill.getWaybillType() == WaybillTypeEnum.ASSIGN.getValue()) {
                // 拿到指派人的ID 判断类型是司机还是承运商
                Long bidderId = cWaybillDetailsVo.getBidderId();
                this.addContants(bidderId, cWaybill.getId());
            }

            // 插入运单明细
            cWaybillDetailsVo.setId(cWaybill.getId());
            this.addCWaybillDeatil(cWaybillDetailsVo);

            // 添加运单地址信息
            this.addCWaybillAddress(cWaybillDetailsVo);

            // 添加运单状态记录 日志
            this.addCWaybillStatusLog(cWaybill, adminUser);

            // 推送运单编码到hyc-operation
            pushWaybillCodeToOperation(cWaybill.getWaybillCode());

        } catch (Exception e) {
            LOGGER.error("create waybill order ERROR : {}.", e);
            throw new BusinessException("创建运单失败。");
        }
        return result;
    }

    /**
     *
     * 推送运单号到hyc-operation
     *
     */
    private void pushWaybillCodeToOperation(String waybillCode) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("waybillCode", waybillCode);
        String url = TmsUrlConstant.PULL_OPERATION_WAYBILL;
        String result = HttpRequestUtil.sendHttpPost(url, map, 10000);
        if (!Objects.equals(result, null)) {
            JSONObject jsonObject = JSONObject.parseObject(result);
            String msg = jsonObject.getString("message");
            Boolean success = jsonObject.getBoolean("success");
            if (!success) {
                LOGGER.error("pushWaybillCodeToOperation error: {}", msg);
                throw new BusinessException("推送运单号异常");
            }
        }
    }

    private void pushServiceOrderCodeToOperation(List<String> serviceOrders) {
        Map<String, Object> map = new HashMap<>();
        map.put("serviceOrders", JSON.toJSON(serviceOrders));
        String url = TmsUrlConstant.PULL_OPERATION_SERVICE;
        String result = HttpRequestUtil.sendHttpPost(url, map, 10000);
        if (!Objects.equals(result, null)) {
            JSONObject jsonObject = JSONObject.parseObject(result);
            String msg = jsonObject.getString("message");
            Boolean success = jsonObject.getBoolean("success");
            if (!success) {
                LOGGER.error("pushServiceOrderCodeToOperation error: {}", msg);
                throw new BusinessException("推送服务订单号异常");
            }
        }
    }

    /**
     * 创建运单 添加运单地址
     *
     * @param cWaybillDetailsVo
     */
    private void addCWaybillAddress(CWaybillDetailsVo cWaybillDetailsVo) throws Exception {
        LOGGER.info("addCWaybillAddress params : {}", cWaybillDetailsVo);
        // 根据地区code 查询名称
        String departProName = this.getAreaService()
                .selectAreaByCodeAndLevel(cWaybillDetailsVo.getDepartProvinceCode(), "1").getName();
        String departCityName = this.getAreaService()
                .selectAreaByCodeAndLevel(cWaybillDetailsVo.getDepartCityCode(), "2").getName();
        String departCountyName = this.getAreaService()
                .selectAreaByCodeAndLevel(cWaybillDetailsVo.getDepartCountyCode(), "3").getName();
        String receiptProName = this.getAreaService()
                .selectAreaByCodeAndLevel(cWaybillDetailsVo.getReceiptProvinceCode(), "1").getName();
        String receiptCityName = this.getAreaService()
                .selectAreaByCodeAndLevel(cWaybillDetailsVo.getReceiptCityCode(), "2").getName();
        String receiptCountyName = this.getAreaService()
                .selectAreaByCodeAndLevel(cWaybillDetailsVo.getReceiptCountyCode(), "3").getName();

        CWaybillAddress cWaybillAddress = new CWaybillAddress();
        cWaybillAddress.setDepartProvinceCode(cWaybillDetailsVo.getDepartProvinceCode());
        cWaybillAddress.setDepartProvinceName(departProName);
        cWaybillAddress.setDepartCityCode(cWaybillDetailsVo.getDepartCityCode());
        cWaybillAddress.setDepartCityName(departCityName);
        cWaybillAddress.setDepartCountyCode(cWaybillDetailsVo.getDepartCountyCode());
        cWaybillAddress.setDepartCountyName(departCountyName);
        cWaybillAddress.setDepartAddr(cWaybillDetailsVo.getDepartAddr());
        cWaybillAddress.setDepartContact(cWaybillDetailsVo.getDepartDriverName());
        cWaybillAddress.setDepartPhone(cWaybillDetailsVo.getDepartDriverPhone());

        cWaybillAddress.setReceiptProvinceCode(cWaybillDetailsVo.getReceiptProvinceCode());
        cWaybillAddress.setReceiptProvinceName(receiptProName);
        cWaybillAddress.setReceiptCityCode(cWaybillDetailsVo.getReceiptCityCode());
        cWaybillAddress.setReceiptCityName(receiptCityName);
        cWaybillAddress.setReceiptCountyCode(cWaybillDetailsVo.getReceiptCountyCode());
        cWaybillAddress.setReceiptCountyName(receiptCountyName);
        cWaybillAddress.setReceiptAddr(cWaybillDetailsVo.getReceiptAddr());
        cWaybillAddress.setReceiptContact(cWaybillDetailsVo.getReceiptDriverName());
        cWaybillAddress.setReceiptPhone(cWaybillDetailsVo.getReceiptDriverPhone());

        cWaybillAddress.setWaybillId(cWaybillDetailsVo.getId());

        BigDecimal distance = mapService.distance(cWaybillDetailsVo.getDepartCityCode(),
                departProName.concat(departCityName), cWaybillDetailsVo.getReceiptCityCode(),
                receiptProName.concat(receiptCityName));
        cWaybillAddress.setDistance(distance);

        cWaybillAddress.setCreateTime(new Date());
        cWaybillAddress.setUpdateTime(new Date());
        this.getCWaybillAddressService().addAddress(cWaybillAddress);
    }

    /**
     * 运单日志
     *
     * @param cWaybill
     * @param adminUser
     */
    private void addCWaybillStatusLog(CWaybill cWaybill, SysAdminUser adminUser) {
        LOGGER.info("addCWaybillStatusLog params : {}", cWaybill);
        try {
            Date currentTime = new Date();
            List<CWaybillStatusLog> list = new ArrayList<CWaybillStatusLog>();
            CWaybillStatusLog log = new CWaybillStatusLog();
            log.setWaybillId(cWaybill.getId());
            if (adminUser == null) {
                UserVo userVo = this.getUserService().getCurrentUserVo();
                log.setUserId(userVo.getId());
                log.setUserName(userVo.getUsername());
            } else {
                log.setUserId(adminUser.getId());
                log.setUserName(adminUser.getUsername());
            }
            log.setCategory(StatusCategoryEnum.PROCESS.getValue());
            log.setStatus(cWaybill.getStatus());
            log.setCreatTime(currentTime);
            log.setUpdateTime(currentTime);
            list.add(log);
            LOGGER.info("create cwaybill insert status log orderLog : {}.", log);

            CWaybillStatusLog payLog = new CWaybillStatusLog();
            payLog.setWaybillId(cWaybill.getId());
            if (adminUser == null) {
                UserVo userVo = this.getUserService().getCurrentUserVo();
                log.setUserId(userVo.getId());
                log.setUserName(userVo.getUsername());
            } else {
                log.setUserId(adminUser.getId());
                log.setUserName(adminUser.getUsername());
            }
            payLog.setCategory(StatusCategoryEnum.PROCESS.getValue());
            payLog.setStatus(cWaybill.getPayStatus());
            payLog.setCreatTime(currentTime);
            payLog.setUpdateTime(currentTime);
            list.add(payLog);
            LOGGER.info("create cwaybill insert status log orderPayLog : {}.", payLog);

            this.getCWaybillStatusLogService().batchInsert(list);
        } catch (Exception e) {
            LOGGER.error("create cwaybill insert status log error : {}.", e);
            throw new BusinessException("添加运单日志异常");
        }
    }

    /**
     * 添加运单明细
     *
     * @param cWaybillDetailsVo
     */
    private void addCWaybillDeatil(CWaybillDetailsVo cWaybillDetailsVo) {
        Date currentTime = new Date();
        try {
            String sorderId = cWaybillDetailsVo.getSorderIds();
            LOGGER.info("create waybill insert details params sorderId : {}.", sorderId);
            List<Long> serviceOrderIdList = new ArrayList<>();
            if (StringUtils.isNotBlank(sorderId)) {
                String[] sorderIds = sorderId.split(",");
                List<String> serviceOrderCodes = Lists.newArrayList();
                for (String string : sorderIds) {
                    // SServiceOrder serviceOrder =
                    // this.getSServiceOrderService().selectById(Long.valueOf(string));
                    LOGGER.info("create waybill insert details sorderId : {}.", string);
                    SServiceOrderVehicle vehicle = this.getSServiceOrderVehicleService().selectByServiceOrderId(string);
                    Long vehicleId = vehicle.getVehicleId();
                    BVehicle bVehicle = this.getBVehicleService().getById(vehicleId);

                    Long brandId = bVehicle.getBrandId();
                    LOGGER.info("create waybill insert details brandId : {}.", brandId);
                    BVehicleBrand bVehicleBrand = this.getBVehicleBrandService().selectById(brandId);

                    // 查询服务订单
                    SServiceOrder sorder = this.getSServiceOrderService().selectById(Long.valueOf(string));
                    if (sorder == null) {
                        LOGGER.info("create cwaybill add cwaybill details sorder is null.");
                        throw new BusinessException("创建运单添加运单明细查询服务订单异常");
                    }

                    CWaybillDetail cWaybillDetail = new CWaybillDetail();
                    cWaybillDetail.setActualDepartTime(cWaybillDetailsVo.getShipmentDate()); // 实际提车时间
                    cWaybillDetail.setActualReceiptTime(cWaybillDetailsVo.getArriveDate()); // 实际送达时间
                    cWaybillDetail.setBrandId(brandId);
                    cWaybillDetail.setBrandName(bVehicleBrand.getBrandName());
                    cWaybillDetail.setVehicleId(vehicleId);
                    cWaybillDetail.setVehicleName(bVehicle.getVehicleName());
                    cWaybillDetail.setVin(vehicle.getVin()); // 车架号

                    cWaybillDetail.setServiceOrderId(Long.valueOf(string)); // 服务订单id
                    cWaybillDetail.setServiceDispatchTimes(sorder.getDispatchTimes() + 1); // 添加服务订单 调度次数
                    cWaybillDetail.setWaybillId(cWaybillDetailsVo.getId()); // 运单 id
                    cWaybillDetail.setSingleFee(cWaybillDetailsVo.getCost().divide(BigDecimal.valueOf(sorderIds.length), 2, RoundingMode.UP));

                    cWaybillDetail.setCreateTime(currentTime);
                    cWaybillDetail.setUpdateTime(currentTime);

                    this.getCWaybillDetailMapper().insertSelective(cWaybillDetail);
                    LOGGER.info("create waybill insert details finish cWaybillDetail : {}.", cWaybillDetail);

                    if (cWaybillDetail.getServiceDispatchTimes() <= 1) {
                        serviceOrderCodes.add(sorder.getOrderCode());
                    }

                    // 根据服务订单查询 查询订单 修改订单状态
                    // 修改客户订单状态 添加日志
                    if (cWaybillDetailsVo.getWaybillType() == WaybillTypeEnum.ASSIGN.getValue()) {
                        this.getSOrderService().updateOrderStatusBySid(Long.valueOf(string));

                        // 保存接单记录 每个运单明细增加一条
                        // 保存接单记录
                        // Long bidId = this.getWaybillBidService().addWayBillBid(Long.valueOf(string), cWaybillDetail.getId(), cWaybillDetailsVo.getBidderId(), true);
                        CWaybillBid bid = new CWaybillBid();
                        bid.setActDriver(cWaybillDetailsVo.getActDriver());
                        bid.setBidderId(cWaybillDetailsVo.getBidderId());
                        bid.setBidderType(cWaybillDetailsVo.getBidderType());
                        bid.setCreateTime(new Date());
                        bid.setWaybillId(cWaybillDetailsVo.getId());
                        bid.setWaybillStatus(cWaybillDetailsVo.getStatus());
                        bid.setOrderId(Long.valueOf(string));
                        bid.setStatus(true);
                        Long bidId = this.getWaybillBidService().insertCWaybillBid(bid);

                        LOGGER.info("接单记录bidId : {}.", bidId);
                    }

                    // 服务订单 调度次数＋1
                    // 创建运单服务订单调度次数是0 才改变状态
                    if (sorder.getDispatchTimes() == 0) {
                        sorder.setStatus(SServiceOrderStatusEnum.WAIT_EXTRACT.getValue());
                    }
                    sorder.setDispatchTimes(sorder.getDispatchTimes() + 1);
                    // this.getSServiceOrderService().addDispatchTimes(Long.valueOf(string));
                    this.getSServiceOrderService().update(sorder);

                    // 判断如果是派单 并且是指派给司机 则发送 提车安排通知
                    if (cWaybillDetailsVo.getWaybillType() == WaybillTypeEnum.ASSIGN.getValue() && cWaybillDetailsVo.getBidderType() == UserTypeEnum.DRIVER.getValue()) {
                        serviceOrderIdList.add(Long.valueOf(string));
                    }
                }
                if (!Collections.isEmpty(serviceOrderIdList)) {
                    this.sendExtractMessage(serviceOrderIdList, cWaybillDetailsVo.getBidderId());
                }

                // 推送服务订单号到hyc-operation
                if (CollectionUtils.isNotEmpty(serviceOrderCodes)) {
                    pushServiceOrderCodeToOperation(serviceOrderCodes);
                }
            }
        } catch (Exception e) {
            LOGGER.error("create waybill insert deatils error : {}.", e);
            throw new BusinessException("插入明细数据异常.");
        }
    }

    /**
     * 消息推送
     *
     * @param serviceOrderId
     * @param waybillCode
     * @param departCountyName
     * @param receiptCountyName
     * @param bidderId
     * @throws BusinessException
     */
    private void sendStanCityMessage(Long serviceOrderId, String waybillCode, String departCountyName, String receiptCountyName, Long bidderId) throws Exception {
        try {
            LOGGER.info("create waybill insert details sorderId : {}.", serviceOrderId);
            SServiceOrderVehicle vehicle = this.getSServiceOrderVehicleService()
                    .selectByServiceOrderId(serviceOrderId + "");
            LOGGER.info("create waybill insert details vehicle : {}.", vehicle);
            Long vehicleId = vehicle.getVehicleId();
            BVehicle bVehicle = this.getBVehicleService().getById(vehicleId);
            LOGGER.info("create waybill insert details bVehicle : {}.", bVehicle);
            Long brandId = bVehicle.getBrandId();
            LOGGER.info("create waybill insert details brandId : {}.", brandId);
            BVehicleBrand bVehicleBrand = this.getBVehicleBrandService().selectById(brandId);
            LOGGER.info("create waybill insert details bVehicleBrand : {}.", bVehicleBrand);
            // 查询最后一次登录设备的UUID
            SUserDevicesExample example = new SUserDevicesExample();
            example.setOrderByClause("id desc");
            example.createCriteria().andUserIdEqualTo(bidderId);
            List<SUserDevices> userDevices = this.getSUserDevicesMapper().selectByExample(example);
            LOGGER.info("sUserDevices size: {}", JSONArray.toJSONString(userDevices));
            if (CollectionUtils.isNotEmpty(userDevices)) {
                SUserDevices devices = userDevices.get(0);
                List<String> aliases = new ArrayList<String>();
                aliases.add(devices.getUuid().replaceAll("-", "").replaceAll("_", ""));
                // 推送消息
                String msg = "尊敬的司机师傅您好，订单" + waybillCode + "（从" + departCountyName + "至" + receiptCountyName + "，"
                        + bVehicleBrand.getBrandName() + bVehicle.getVehicleName() + "）已派发给您，请您尽快上线接单！";
                LOGGER.info("msg: {}, devices: {}", msg, devices.getUuid());
                this.getJPushService().sendMsgStanCityByAliases(aliases, msg, "2");
            }
        } catch (Exception e) {
            LOGGER.error("create waybill insert deatils error : {}.", e);
            throw new BusinessException("派单消息推送异常");
        }
    }

    /**
     * 生成运单 如果是派单 判断指派人 司机／承运商
     *
     * @param userId
     * @param waybillId
     */
    private void addContants(Long userId, Long waybillId) {
        Date currentTime = new Date();
        try {
            LOGGER.info("create cwaybill add contants params userId : {}, waybillId : {}.", userId, waybillId);
            SUser user = this.getUserService().getById(userId);
            if (user != null && user.getUserType() == UserTypeEnum.DRIVER.getValue()) {
                CDriverCertinfo driverInfo = this.getTruckInfoService().queryDriverInfoById(userId);
                if (driverInfo == null) {
                    LOGGER.info("create cwaybill add contants params driverInfo is not null");
                    throw new BusinessException("添加司机信息认证信息为空");
                }
                CTruckInfo truckInfo = this.getTruckInfoService().queryTruckInfoById(userId);
                if (truckInfo == null) {
                    LOGGER.info("create cwaybill add contants params truckInfo is not null");
                    throw new BusinessException("添加司机信息车辆信息为空");
                }
                LOGGER.info("create cwaybill add contacts userId : {}, waybillId : {}.", userId, waybillId);

                // 如果指派人为司机 则插入到contacts表中
                CWaybillContacts cWaybillContacts = new CWaybillContacts();
                cWaybillContacts.setCreateTime(currentTime);
                cWaybillContacts.setUpdateTime(currentTime);
                cWaybillContacts.setContact(user.getRealName());
                cWaybillContacts.setIdno(driverInfo.getIdno());
                cWaybillContacts.setLicenseNumner(truckInfo.getTractorNumber());
                cWaybillContacts.setPhone(user.getPhone());
                cWaybillContacts.setWaybillId(waybillId);
                List<CWaybillContacts> list = new ArrayList<CWaybillContacts>();
                cWaybillContacts.setType(WaybillContactsTypeEnum.DRIVER.getValue());
                list.add(cWaybillContacts);
                LOGGER.info("create cwaybill add contacts userId : {}, waybillId : {}, contactsType : {}.", userId,
                        waybillId, WaybillContactsTypeEnum.DRIVER.getValue());
                CWaybillContacts cWaybillContacts20 = new CWaybillContacts();
                BeanUtils.copyProperties(cWaybillContacts, cWaybillContacts20);
                cWaybillContacts20.setType(WaybillContactsTypeEnum.DEPARTPERSON.getValue());
                list.add(cWaybillContacts20);
                LOGGER.info("create cwaybill add contacts userId : {}, waybillId : {}, contactsType : {}.", userId,
                        waybillId, WaybillContactsTypeEnum.DEPARTPERSON.getValue());
                CWaybillContacts cWaybillContacts30 = new CWaybillContacts();
                BeanUtils.copyProperties(cWaybillContacts, cWaybillContacts30);
                cWaybillContacts30.setType(WaybillContactsTypeEnum.RECEIPTPERSON.getValue());
                list.add(cWaybillContacts30);
                LOGGER.info("create cwaybill add contacts userId : {}, waybillId : {}, contactsType : {}.", userId,
                        waybillId, WaybillContactsTypeEnum.RECEIPTPERSON.getValue());

                this.getCWaybillContactsService().batchInsert(list);
            } else {
                LOGGER.info("add contancts grab user is company, not add contancts userId : {}.", userId);
            }
        } catch (Exception e) {
            LOGGER.error("create cwaybill add contants error : {}.", e);
            throw new BusinessException("创建运单添加交接人信息异常.");
        }
    }

    /**
     * 创建运单 判断参数为空
     *
     * @param cWaybillDetailsVo
     * @return
     */
    private Result<String> validateParams(CWaybillDetailsVo cWaybillDetailsVo) {
        Result<String> result = new Result<String>(true, null, "创建运单参数检验完成");
        if (StringUtils.isBlank(cWaybillDetailsVo.getDepartProvinceCode())) {
            LOGGER.info("create waybill order departProviceCode is not null");
            result.setSuccess(false);
            result.setMessage("起运省code不能为空");
            return result;
        } else if (StringUtils.isBlank(cWaybillDetailsVo.getDepartCityCode())) {
            LOGGER.info("create waybill order departcityCode is not null");
            result.setSuccess(false);
            result.setMessage("起运市code不能为空");
            return result;
        } else if (StringUtils.isBlank(cWaybillDetailsVo.getDepartCountyCode())) {
            LOGGER.info("create waybill order departCountyCode is not null");
            result.setSuccess(false);
            result.setMessage("起运区县code不能为空");
            return result;
        } else if (cWaybillDetailsVo.getShipmentDate() == null) {
            LOGGER.info("create waybill order ShipmentDate is not null");
            result.setSuccess(false);
            result.setMessage("起运日期不能为空");
            return result;
        } else if (cWaybillDetailsVo.getArriveDate() == null) {
            LOGGER.info("create waybill order ArriveDate is not null");
            result.setSuccess(false);
            result.setMessage("到达日期不能为空");
            return result;
        } else if (cWaybillDetailsVo.getCost() == null) {
            LOGGER.info("create waybill order cost is not null");
            result.setSuccess(false);
            result.setMessage("运费不能为空");
            return result;
        } else if (StringUtils.isBlank(cWaybillDetailsVo.getSorderIds())) {
            LOGGER.info("create waybill order detailIds is not null");
            result.setSuccess(false);
            result.setMessage("服务订单ID不能为空");
            return result;
        } else if (cWaybillDetailsVo.getWaybillType() == null) {
            LOGGER.info("create waybill order waybilltype is not null");
            result.setSuccess(false);
            result.setMessage("运单接单类型不能为空");
            return result;
        }
        return result;
    }

    /**
     * 查询运单参考价
     *
     * @param cWaybillVo
     * @return
     */
    @Override
    public String selectPrice(CWaybillDetailsVo cWaybillVo) throws Exception {
        LOGGER.info("selectPrice params : {}", cWaybillVo);
        /**
         * 运费 该价格模型为平台报给托运人的运费价格模型。 运费=（运距*城市级别* +距离浮动因数）*车型系数。
         * 运距为第一次从高德A运距系数PI取得的城市距离，存入平台后端运距表，不区分起点和终点城市。
         */
        String depaCityCode = cWaybillVo.getDepartCityCode();
        String destCityCode = cWaybillVo.getReceiptCityCode();

        LOGGER.info("selectPrice params : {}, {}", depaCityCode, destCityCode);
        if (StringUtils.isBlank(depaCityCode)) {
            LOGGER.error("selectPrice depaCityCode must not be null");
            throw new BusinessException("发运城市code不能为空！");
        }
        if (StringUtils.isBlank(destCityCode)) {
            LOGGER.error("selectPrice destCityCode must not be null");
            throw new BusinessException("收货城市code不能为空！");
        }
        String depaAddr = cWaybillVo.getDepartProvinceName() + cWaybillVo.getDepartCityName();
        String destAddr = cWaybillVo.getReceiptProvinceName() + cWaybillVo.getReceiptCityName();

        // 查询城市级别系数
        BigDecimal destinationCoefficient = this.getAreaService().getCityCoefficientByCode(destCityCode);

        // 查询运距
        BigDecimal distance = mapService.distance(depaCityCode, depaAddr, destCityCode, destAddr);

        // 获取运输费率
        SShippingFee shippingFee = this.getBFeeTypeService().getShippingFeeByFeeCode(BFeeTypeEnum.SHIPPING, distance);

        // 获取车型因子系数
        Map<String, BigDecimal> factorRatios = this.getVehicleClassService().getFactorRatio();

        return countAClassOfVehicleShippingFeeByVehicleClass(distance, destinationCoefficient, shippingFee,
                factorRatios, null) + "";
    }

    /**
     * 计算运费
     *
     * @param distance
     * @param destinationCoefficient
     * @param shippingFee
     * @param factorRatios
     * @param details
     * @return
     */
    private BigDecimal countAClassOfVehicleShippingFeeByVehicleClass(BigDecimal distance,
                                                                     BigDecimal destinationCoefficient, SShippingFee shippingFee, Map<String, BigDecimal> factorRatios,
                                                                     List<CWaybillDetail> details) {
        LOGGER.info("countAClassOfVehicleShippingFeeByVehicleClass params : {}, {}, {}, {}, {}", distance, destinationCoefficient, shippingFee, factorRatios, details);
        BigDecimal vehicleShipping = BigDecimal.valueOf(0.00);
        // 一辆车的运费（运费=(运距系数*运距*城市基本系数+距离浮动系数)*车型费率，计算结果不小于300）
        BigDecimal vehicleShippingFee = shippingFee.getRate().multiply(distance).multiply(destinationCoefficient)
                .add(shippingFee.getSubsidy());

        // 若运费少于300则按300计算
        if (-1 == vehicleShippingFee.compareTo(BigDecimal.valueOf(300))) {
            vehicleShippingFee = BigDecimal.valueOf(300);
        }

        for (CWaybillDetail cWaybillDetail : details) {
            Long vehicleId = cWaybillDetail.getVehicleId();
            BVehicle vehicle = this.getBVehicleMapper().selectByPrimaryKey(vehicleId);

            // *车型因子系数 没有车型则为M
            vehicleShippingFee = vehicleShippingFee
                    .multiply(factorRatios.get(StringUtils.isBlank(vehicle.getSysVehicleClass()) == true
                            ? BVehicleConstant.DEFAULT_VEHICLE_CLASS : vehicle.getSysVehicleClass()));
        }

        return vehicleShipping;
    }

    /**
     * 根据服务订单 查询所有运单
     *
     * @param serviceOrderId
     * @return
     */
    @Override
    public List<CWaybillByIdVo> selectBySid(Long serviceOrderId) {
        LOGGER.info("select cwaybills by service orderId params serviceOrderId : {}.", serviceOrderId);
        List<CWaybillByIdVo> cWaybills = new ArrayList<CWaybillByIdVo>();
        try {
            LOGGER.info("select cwaybills by service orderId select cwaybilldetails");
            CWaybillDetailExample detailExample = new CWaybillDetailExample();
            detailExample.createCriteria().andServiceOrderIdEqualTo(serviceOrderId);
            List<CWaybillDetail> cWaybillDetails = this.getCWaybillDetailMapper().selectByExample(detailExample);
            List<Long> ids = new ArrayList<Long>();
            for (CWaybillDetail cWaybillDetail : cWaybillDetails) {
                ids.add(cWaybillDetail.getWaybillId());
            }
            LOGGER.info("select cwaybills by service orderId select cwaybilldetails cwaybillids : {}.", ids);

            if (!CollectionUtils.isEmpty(ids)) {
                // CWaybillExample waybillExample = new CWaybillExample();
                // waybillExample.createCriteria().andIdIn(ids);
                cWaybills = this.getCWaybillViewMapper().selectByIds(ids);
                LOGGER.info("select cwaybills by service orderId finish count : {}", cWaybills.size());
            }
        } catch (Exception e) {
            LOGGER.error("select cwaybills by service orderId error : {}.", e);
            e.printStackTrace();
        }
        return cWaybills;
    }

    /**
     * 查询运单列表
     *
     * @param page
     * @param waybillVo
     * @return
     * @throws Exception
     */
    @Override
    public Map<String, Object> list(PageVo page, WaybillNewsVo waybillVo) throws Exception {
        LOGGER.info("list params : {}, {}", page, waybillVo);
        Map<String, Object> map = new HashMap<String, Object>();
        try {
            page.setTotalRecord(this.getWaybillMapper().recordCount(waybillVo));
            List<WaybillVo> waybillVos = this.getWaybillMapper().selectWaybillByCondition(page, waybillVo);
            map.put("page", page);
            map.put("waybillVo", waybillVos);
        } catch (Exception e) {
            LOGGER.error("selectWaybill error : {}", e);
            e.printStackTrace();
        }
        return map;
    }

    /**
     * 根据运单ID 查询运单详情
     *
     * @param id
     * @return
     */
    @Override
    public CWaybillByIdVo selectById(Long id) {
        LOGGER.info("selectById param : {}", id);
        try {
            LOGGER.info("select cwaybillbyidvo id : {}.", id);
            CWaybillByIdVo vo = this.getCWaybillViewMapper().selectByPrimaryKey(id);
            List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
            List<CWaybillAttach> attachs = vo.getAttachs();
            List<CWaybillContacts> contacts = vo.getContacts();
            if (CollectionUtils.isNotEmpty(contacts)) {
                for (CWaybillContacts cts : contacts) {
                    String idno = cts.getIdno();
                    if (StringUtils.isNotBlank(idno)) {
                        cts.setIdno(HYCUtils.decryptAppSensitiveInformation(cts.getIdno()));
                    } else {
                        cts.setIdno("");
                    }
                }
            }
            if (CollectionUtils.isNotEmpty(attachs)) {
                for (CWaybillAttach cWaybillAttach : attachs) {
                    Map<String, Object> map = new HashMap<String, Object>();
                    map.put("key", cWaybillAttach.getPicKey());
                    map.put("url", QiniuUtils.generateDownloadTicket(cWaybillAttach.getPicKey(), ""));
                    map.put("desc", AttachCategoryEnumWaybill.SEND.getText());
                    map.put("type", cWaybillAttach.getType());
                    map.put("waybillid", vo.getId());
                    LOGGER.info("select cwaybillbyidvo id : {}, attachsId : {}.", id, cWaybillAttach.getId());
                    list.add(map);
                }
                vo.setAttachsList(list);
            }
            return vo;
        } catch (Exception e) {
            LOGGER.error("select cwaybillbyidvo id : {}, error : {}.", id, e);
            throw new BusinessException("根据运单ID查询运单详情异常");
        }
    }

    @Override
    public WaybillContactsVo selectWaybillContact(WaybillContactsVo vo) throws Exception {
        LOGGER.info("selectWaybillContact params : {}", vo);
        if (vo.getType() == null) {
            LOGGER.info("Receipt types cannot be empty");
            throw new BusinessException("交接单类型不能为空");
        } else if (vo.getId() == null) {
            LOGGER.info("waybillId is not null");
            throw new BusinessException("运单ID不能为空");
        } else if (vo.getAttachType() == null) {
            LOGGER.info("attachtype is not null");
            throw new BusinessException("附件类型不能为空");
        }
        WaybillContactsVo wContactsVo = new WaybillContactsVo();
        try {
            if (vo.getAttachType() == AttachCategoryEnumWaybill.RECEIPT.getValue()) {
                wContactsVo = this.getWaybillMapper().selectWaybillLiftContact(vo);
            } else if (vo.getAttachType() == AttachCategoryEnumWaybill.DELIVER.getValue()) {
                wContactsVo = this.getWaybillMapper().selectWaybillDealContact(vo);
            }
            if (wContactsVo != null) {
                List<CWaybillAttach> cWaybillAttachs = wContactsVo.getAttachs();
                if (StringUtils.isNotBlank(wContactsVo.getIdno())) {
                    wContactsVo.setIdno(HYCUtils.decryptAppSensitiveInformation(wContactsVo.getIdno()));
                }
                if (CollectionUtils.isNotEmpty(cWaybillAttachs)) {
                    for (CWaybillAttach cWaybillAttach : cWaybillAttachs) {
                        cWaybillAttach.setPicKey(QiniuUtils.generateDownloadTicket(cWaybillAttach.getPicKey(), ""));
                    }
                }
            }
            LOGGER.info("selectWaybillContact record : {}", wContactsVo);
            return wContactsVo;
        } catch (Exception e) {
            LOGGER.error("selectWaybillContact is error : {}", e);
            throw new BusinessException("查询交接单信息错误");
        }
    }

    @Override
    public long liftAudit(Long waybillId) throws Exception {
        LOGGER.info("liftAudit param waybillId : {}", waybillId);
        if (waybillId == null) {
            LOGGER.info("The waybillId can not be empty");
            throw new BusinessException("运单ID不能为空");
        }
        CWaybill cWaybill = this.getCWaybillMapper().selectByPrimaryKey(waybillId);
        if (cWaybill == null) {
            LOGGER.info("waybill is empty");
            throw new BusinessException("此运单不存在");
        }
        // 判断运单状态是否为：“已提车”
        if (WaybillStatusEnum.EXTRACTED.getValue() == cWaybill.getStatus()) {
            cWaybill.setStatus(WaybillStatusEnum.WAITSTART.getValue());
            // 更新运单状态为：“待发车”
            this.getCWaybillMapper().updateByPrimaryKeySelective(cWaybill);
        }
        // 查询运单明细
        CWaybillDetailExample example = new CWaybillDetailExample();
        example.createCriteria().andWaybillIdEqualTo(waybillId);
        List<CWaybillDetail> details = this.getCWaybillDetailMapper().selectByExample(example);
        if (CollectionUtils.isEmpty(details)) {
            LOGGER.info("waybilldetail is empty");
            throw new BusinessException("运单明细不存在");
        }
        List<Long> longs = new ArrayList<Long>();
        List<Long> serviceId = new ArrayList<Long>();
        for (CWaybillDetail detail : details) {
            longs.add(detail.getServiceOrderId());
            if (detail.getServiceDispatchTimes() == 1) {
                serviceId.add(detail.getServiceOrderId());
            }
        }
        // 查询服务订单
        SServiceOrderExample serviceOrderExample = new SServiceOrderExample();
        serviceOrderExample.createCriteria().andIdIn(longs);
        List<SServiceOrder> sOrders = this.getSServiceOrderMapper().selectByExample(serviceOrderExample);
        if (CollectionUtils.isEmpty(sOrders)) {
            LOGGER.info("serviceOrder is empty");
            throw new BusinessException("服务订单不存在");
        }
        for (SServiceOrder sServiceOrder : sOrders) {
            // 判断服务订单状态是否为：“待提车”
            if (SServiceOrderStatusEnum.WAIT_EXTRACT.getValue() == sServiceOrder.getStatus()) {
                // 更新服务订单状态为：“已提车”
                sServiceOrder.setStatus(SServiceOrderStatusEnum.HAVE_EXTRACTED.getValue());
                this.getSServiceOrderMapper().updateByPrimaryKeySelective(sServiceOrder);
            }
        }
        if (serviceId.size() > 0) {
            SServiceOrderExample serviceOrdere = new SServiceOrderExample();
            serviceOrdere.createCriteria().andIdIn(serviceId);
            List<SServiceOrder> serviceOrders = this.getSServiceOrderMapper().selectByExample(serviceOrdere);
            if (CollectionUtils.isNotEmpty(serviceOrders)) {
                for (SServiceOrder sServiceOrder : serviceOrders) {
                    SServiceOrderTrail trail = new SServiceOrderTrail();
                    trail.setInfo(SServiceOrderStatusEnum.getByValue(sServiceOrder.getStatus()).getText());
                    trail.setServiceOrderId(sServiceOrder.getId());
                    trail.setStatus(SServiceOrderStatusEnum.getByValue(sServiceOrder.getStatus()).getValue());
                    trail.setType(SServiceOrderTrailTypeEnum.SERVICE_ORDER_STATUS.getValue());
                    trail.setCreateTime(new Date());
                    // 写入服务订单物流信息
                    this.getSServiceOrderTrailMapper().insertSelective(trail);
                }
            }
        }
        return 0;
    }

    @Override
    public long liftAuditRebut(Long waybillId) throws Exception {
        LOGGER.info("liftAuditRebut param waybillId : {}", waybillId);
        if (waybillId == null) {
            LOGGER.info("The waybillId can not be empty");
            throw new BusinessException("运单ID不能为空");
        }
        CWaybill cWaybill = this.getCWaybillMapper().selectByPrimaryKey(waybillId);
        if (cWaybill == null) {
            LOGGER.info("waybill is empty");
            throw new BusinessException("此运单不存在");
        }
        // 判断运单状态是否为：“已提车”
        if (WaybillStatusEnum.EXTRACTED.getValue() == cWaybill.getStatus()) {
            cWaybill.setStatus(WaybillStatusEnum.WAITEXTRACTED.getValue());
            // 更新运单状态为：“待提车”
            this.getCWaybillMapper().updateByPrimaryKeySelective(cWaybill);
        }
        return 0;
    }

    @Override
    public long dealAudit(Long waybillId) throws Exception {
        LOGGER.info("dealAudit param waybillId : {}", waybillId);
        if (waybillId == null) {
            LOGGER.info("The waybillId can not be empty");
            throw new BusinessException("运单ID不能为空");
        }
        CWaybill cWaybill = this.getCWaybillMapper().selectByPrimaryKey(waybillId);
        if (cWaybill == null) {
            LOGGER.info("waybill is empty");
            throw new BusinessException("此运单不存在");
        }

        // 判断运单状态是否为：“已交车”
        if (WaybillStatusEnum.COMPLETED.getValue() == cWaybill.getStatus()) {
            cWaybill.setStatus(WaybillStatusEnum.DONE.getValue());
            if (cWaybill.getBidderType() == UserTypeEnum.DRIVER.getValue()) {
                // 如果是司机 更新运单支付状态未 已支付
                cWaybill.setPayStatus(PaymentStatusEnum.ALREADY_PAID.getValue());
            }
            // 更新运单状态为：“已完成”
            this.getCWaybillMapper().updateByPrimaryKeySelective(cWaybill);

            int userType = cWaybill.getBidderType();
            if (userType == UserTypeEnum.DRIVER.getValue()) {// 司机接单 打钱 给司机
                Long userId = cWaybill.getActDriver();
                LOGGER.info("dealAudit driver query jiaoche add scores params ActDriver : {}, userType : {}.", userId, userType);

                // 给司机账户 增加余额 ＝ 运费
                this.addDriverBalance(cWaybill);
            } else if (userType == UserTypeEnum.COMPANY.getValue()) {// 物流企业接单 向流水明细中加入数据 生成账单
                // 添加明细数据
                this.addTurnover(cWaybill);
            }

            // 查询运单明细
            CWaybillDetailExample example = new CWaybillDetailExample();
            example.createCriteria().andWaybillIdEqualTo(waybillId);
            List<CWaybillDetail> details = this.getCWaybillDetailMapper().selectByExample(example);
            if (CollectionUtils.isEmpty(details)) {
                LOGGER.info("waybilldetail is empty");
                throw new BusinessException("运单明细不存在");
            }
            List<Long> longs = new ArrayList<Long>();
            for (CWaybillDetail detail : details) {
                longs.add(detail.getServiceOrderId());
                /** if(cWaybill.getIsVeneer()){
                 detail.setIsLastTime(true);
                 this.getCWaybillDetailMapper().updateByPrimaryKeySelective(detail);
                 SServiceOrder serviceOrder = new SServiceOrder();
                 serviceOrder.setId(detail.getServiceOrderId());
                 serviceOrder.setStatus(SServiceOrderStatusEnum.HAVE_DELIVERY.getValue());
                 this.getSServiceOrderMapper().updateByPrimaryKeySelective(serviceOrder);
                 } */
            }

            // 同城运单 交车照片审核的时候 运单完成
            if (cWaybill.getIsVeneer()) {
                return this.getSServiceOrderService().updateServiceStatus(details.get(0).getServiceOrderId().toString(), SServiceOrderStatusEnum.HAVE_DELIVERY.getValue() + "");
            }

            SServiceOrderExample serviceOrderExample = new SServiceOrderExample();
            CWaybillAddressExample addressExample = new CWaybillAddressExample();
            addressExample.createCriteria().andWaybillIdEqualTo(waybillId);
            CWaybillAddress address = this.getCWaybillAddressService().selectByExample(addressExample);
            if (null != address) {
                // 查询服务订单 更新服务订单当前位置 城市
                serviceOrderExample.createCriteria().andIdIn(longs);
                List<SServiceOrder> sOrders = this.getSServiceOrderMapper().selectByExample(serviceOrderExample);
                if (CollectionUtils.isNotEmpty(sOrders)) {
                    for (SServiceOrder sServiceOrder : sOrders) {
                        sServiceOrder.setCurrentAddr(address.getReceiptCityName());
                        this.getSServiceOrderMapper().updateByPrimaryKeySelective(sServiceOrder);
                    }
                }
            }

            /** if(cWaybill.getIsVeneer()){
             // 运单交车审核 如果所有的服务订单都已经交车 则 客户订单改为已交车状态
             serviceOrderExample.createCriteria().andIdIn(longs).andStatusLessThan(SServiceOrderStatusEnum.HAVE_DELIVERY.getValue());
             List<SServiceOrder> list = this.getSServiceOrderMapper().selectByExample(serviceOrderExample);
             if(list.size() == 1){
             SOrder sOrder = new SOrder();
             sOrder.setId(list.get(0).getCustomerOrderId());
             sOrder.setStatus(COrderStatusEnum.COMPLETED.getValue());
             this.getSOrderMapper().updateByPrimaryKeySelective(sOrder);
             }
             } */
        }
        return 0;
    }

    @Override
    public long dealAuditRebut(Long waybillId) throws Exception {
        LOGGER.info("dealAuditRebut param waybillId : {}", waybillId);
        if (waybillId == null) {
            LOGGER.info("The waybillId can not be empty");
            throw new BusinessException("运单ID不能为空");
        }
        CWaybill cWaybill = this.getCWaybillMapper().selectByPrimaryKey(waybillId);
        if (cWaybill == null) {
            LOGGER.info("waybill is empty");
            throw new BusinessException("此运单不存在");
        }

        // 判断运单状态是否为：“已交车”
        if (WaybillStatusEnum.COMPLETED.getValue() == cWaybill.getStatus()) {
            cWaybill.setStatus(WaybillStatusEnum.WAITCOMPLETE.getValue());
            // 更新运单状态为：“待交车”
            this.getCWaybillMapper().updateByPrimaryKeySelective(cWaybill);

            // 查询运单明细
            CWaybillDetailExample example = new CWaybillDetailExample();
            example.createCriteria().andWaybillIdEqualTo(waybillId);
            List<CWaybillDetail> details = this.getCWaybillDetailMapper().selectByExample(example);
            if (CollectionUtils.isEmpty(details)) {
                LOGGER.info("waybilldetail is empty");
                throw new BusinessException("运单明细不存在");
            }
            List<Long> longs = new ArrayList<Long>();
            for (CWaybillDetail detail : details) {
                longs.add(detail.getServiceOrderId());
            }
        }
        return 0;
    }

    //
    @Override
    public void sendDeliveryMessage(List<Long> serviceOrderIdList) {
        LOGGER.info("stan company grab one order sendExtractMessage params serviceOrderIdList : {}.", serviceOrderIdList);
        try {
            Map<Long, List<Long>> map = new HashMap<>();
            Boolean isVeneer = false;
            for (Long sId : serviceOrderIdList) {
                SServiceOrder sServiceOrder = this.getSServiceOrderService().selectById(sId);
                Long customerOrderId = sServiceOrder.getCustomerOrderId();

                isVeneer = sServiceOrder.getIsVeneer();

                if (map.keySet().contains(customerOrderId)) {
                    List<Long> list = map.get(customerOrderId);
                    list.add(sId);
                    map.put(customerOrderId, list);
                } else {
                    List<Long> list = new ArrayList<>();
                    list.add(sId);
                    map.put(customerOrderId, list);
                }
            }

            if (isVeneer) {
                Set<Long> keySet = map.keySet();
                for (Long long1 : keySet) {
                    sendVeneerDeliveryMessage(long1);
                }
            } else {
                Set<Long> keySet = map.keySet();
                for (Long long1 : keySet) {
                    Integer carAmount = map.get(long1).size();
                    sendChengjiDeliveryMessage(long1, carAmount);
                }
            }

        } catch (Exception e) {
            LOGGER.error("stan compaby grab one order sendExtractMessage error : {}.", e);
            throw new BusinessException("安排司机提车,发送提车安排通知异常");
        }
    }

    private void sendChengjiDeliveryMessage(Long long1, Integer carAmount) {
        try {
            LOGGER.info("send chengji message jiaoche info : {}.", long1);
            SOrder sorder = this.getSOrderService().selectByPrimaryKey(long1);
            String departAddr = sorder.getDepartCityName();
            String receiptAddr = sorder.getReceiptCityName();
            String orderCode = sorder.getOrderCode();

            String tplValue = URLEncoder.encode("#departAddr#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(departAddr, JavaSmsApi.getENCODING());
            tplValue += "&" + URLEncoder.encode("#receiptAddr#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(receiptAddr, JavaSmsApi.getENCODING());
            tplValue += "&" + URLEncoder.encode("#orderCode#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(orderCode, JavaSmsApi.getENCODING());
            tplValue += "&" + URLEncoder.encode("#carAmount#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(carAmount + "", JavaSmsApi.getENCODING());

            long tplId = JavaSmsApi.DELIVERY_TPL_ID;
            // String phone = sorder.getDepartPhone();
            String phone = null;
            Long userId = sorder.getUserId();
            SUser userOrder = this.getUserService().selectByPrimaryKey(userId);
            if (null != userOrder) {
                phone = userOrder.getPhone();
            }
            if (null != phone) {
                this.getSendMessageService().sendMessage(tplId, tplValue, phone);
            }
        } catch (Exception e) {
            LOGGER.error("send chengji message jiaoche info : {}, error : {}.", long1, e);
            throw new BusinessException("城际发送交车短信异常");
        }
    }

    private void sendVeneerDeliveryMessage(Long long1) {
        try {
            LOGGER.info("send veneer message jiaoche info : {}.", long1);
            SOrder sorder = this.getSOrderService().selectByPrimaryKey(long1);
            SServiceOrderExample serviceOrderExample = new SServiceOrderExample();
            serviceOrderExample.createCriteria().andCustomerOrderIdEqualTo(long1);
            List<SServiceOrder> serviceOrders = this.getSServiceOrderService().selectByExample(serviceOrderExample);
            String vehicle = "";
            if (!serviceOrders.isEmpty()) {
                SServiceOrderVehicle serviceOrderId = this.getSServiceOrderVehicleService().selectByServiceOrderId(serviceOrders.get(0).getId() + "");

                Long brandId = serviceOrderId.getBrandId();
                Long vehicleId = serviceOrderId.getVehicleId();
                BVehicleBrand brand = this.getBVehicleBrandService().selectById(brandId);
                BVehicle bVehicle = this.getBVehicleService().selctById(vehicleId);
                vehicle = brand.getBrandName() == null ? "" : brand.getBrandName().concat(bVehicle.getVehicleName() == null ? "" : bVehicle.getVehicleName());
            } else {
                vehicle = sorder.getOrderCode();
            }

            String tplValue = URLEncoder.encode("#vehicle#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(vehicle, JavaSmsApi.getENCODING());
            long tplId = JavaSmsApi.VENEER_DELIVERY_TPL_ID;

            // String phone = null;
            // Long userId = sorder.getUserId();
            // SUser userOrder = this.getUserService().selectByPrimaryKey(userId);
            // if(null != userOrder){
            // 	phone = userOrder.getPhone();
            // }
            String departPhone = sorder.getDepartPhone();
            if (null != departPhone) {
                this.getSendMessageService().sendMessage(tplId, tplValue, departPhone);
            }


            // 推送消息
            String departCityName = sorder.getDepartCountyName();
            String receiptCityName = sorder.getReceiptCountyName();

            SUserDevicesExample example = new SUserDevicesExample();
            example.setOrderByClause("id desc");
            example.createCriteria().andUserIdEqualTo(sorder.getUserId());
            List<SUserDevices> sUserDevices = this.getSUserDevicesMapper().selectByExample(example);
            if (CollectionUtils.isNotEmpty(sUserDevices)) {
                SUserDevices devices = sUserDevices.get(0);
                List<String> aliases = new ArrayList<String>();
                aliases.add(devices.getUuid().replaceAll("-", "").replaceAll("_", ""));
                // 推送消息
                String msg = "尊敬的客户,从" + departCityName + "至" + receiptCityName + "," + vehicle + "已交车。请知悉!";
                LOGGER.info("msg: {}, devices: {}", msg, devices.getUuid());
                this.getJPushService().sendMsgKyleByAliases(aliases, msg);
            }
        } catch (Exception e) {
            LOGGER.error("send veneer message jiaoche info : {}, error : {}.", long1, e);
            throw new BusinessException("同城发送交车短信异常");
        }
    }

    // 物流企业 客户订单 添加流水明细
    private void addTurnover(CWaybill cWaybill) {
        LOGGER.info("cwaybill jiaoche picture dealAudit pass add stan company turnover : {}.", cWaybill);
        try {
            List<CTurnover> list = new ArrayList<>();
            CTurnover cTurnover = new CTurnover();

            SUser user = this.getUserService().selectByPrimaryKey(cWaybill.getBidderId());

            cTurnover.setPayType(AccPaytypeEnum.ORDER.getValue());
            cTurnover.setStatus(AccTurnoverStatusEnum.WAIT.getValue());
            cTurnover.setUserId(user.getId());
            cTurnover.setUserName(user.getRealName());
            cTurnover.setUserType(user.getUserType());
            cTurnover.setOrderId(cWaybill.getId());
            cTurnover.setOrderFee(cWaybill.getCost().abs());
            cTurnover.setOrderActPay(cWaybill.getCost().abs());
            cTurnover.setCreateTime(new Date());
            cTurnover.setUpdateTime(new Date());

            // 账单流水添加公司信息
            Long companyId = this.getBCompanyUserService().getCompanyIdByUserId(user.getId());
            if (null != companyId) {
                cTurnover.setCompanyId(companyId);
                Map<String, Object> companyNameMap = this.getCompanyService().selectById(companyId);
                BCompany bCompany = (BCompany) companyNameMap.get("companyData");
                if (null != bCompany) {
                    cTurnover.setCompanyName(bCompany.getCompanyName());
                }
            }

            list.add(cTurnover);
            this.getCAccntTurnOverService().addDetailsAndLedger(list, 0);
        } catch (Exception e) {
            LOGGER.error("cwaybill jiaoche picture dealAudit pass add stan company turnover : {}.", e);
            throw new BusinessException("交车照片审核通过添加流水明细异常");
        }
    }

    /**
     * 运单确认交车 司机增加积分
     * @param cWaybill
     */
    /** private void addDriverScores(CWaybill cWaybill, BigDecimal distance) {
     LOGGER.info("dealAudit addDriverScores params cWaybill : {}.", JSON.toJSONString(cWaybill));
     try {
     this.getBScoresService().addTotalDistance(cWaybill, distance);
     } catch (Exception e) {
     LOGGER.info("dealAudit addDriverScores params cWaybill : {}, error : {}.", JSON.toJSONString(cWaybill), e);
     throw new BusinessException("运单确认交车,司机添加积分异常");
     }

     } */

    /**
     *  运单确认交车 给司机账户增加余额
     *
     * @param cWaybill
     */
    private void addDriverBalance(CWaybill cWaybill) {
        LOGGER.info("dealAudit addDriverBalance params cWaybill : {}.", cWaybill);
        try {
            List<CTurnover> cTurnovers = new ArrayList<CTurnover>();
            CTurnover cTurnover = new CTurnover();
            cTurnover.setCreateTime(new Date());
            cTurnover.setUpdateTime(new Date());
            cTurnover.setOrderId(cWaybill.getId());
            cTurnover.setOrderActPay(cWaybill.getCost());
            cTurnover.setOrderFee(cWaybill.getCost());
            cTurnover.setPayType(AccPaytypeEnum.ORDER.getValue());
            cTurnover.setStatus(AccTurnoverStatusEnum.DONE.getValue());
            cTurnover.setUserId(cWaybill.getBidderId());
            cTurnover.setUserType(UserTypeEnum.DRIVER.getValue());
            cTurnover.setUserName(this.getUserService().getById(cWaybill.getBidderId()).getRealName());
            cTurnovers.add(cTurnover);
            LOGGER.info("dealAudit addDriverBalance params cWaybill : {}, add balance : {}.", JSON.toJSONString(cWaybill), JSON.toJSONString(cTurnover));
            this.getCAccntTurnOverService().addDetailsAndLedger(cTurnovers, 0);
        } catch (Exception e) {
            LOGGER.info("dealAudit addDriverBalance params cWaybill : {}, error : {}.", JSON.toJSONString(cWaybill), e);
            throw new BusinessException("运单确认交车,司机账户添加余额异常");
        }
    }

    @Override
    public List<DeReDetailVo> getExinfo(long caybillId, int dispatchTimes) {
        LOGGER.info("getExinfo params : {}, {}", caybillId, dispatchTimes);
        if (0 == caybillId) {
            LOGGER.error("getExinfo caybillId must not be 0");
            throw new IllegalArgumentException("运单id不能是0");
        }

        CWaybillDetailExample example = new CWaybillDetailExample();
        CWaybillDetailExample.Criteria criteria = example.createCriteria().andWaybillIdEqualTo(caybillId);
        if (0 != dispatchTimes) {
            criteria.andServiceDispatchTimesEqualTo(dispatchTimes);
        }
        List<CWaybillDetail> list = cWaybillDetailMapper.selectByExample(example);
        if (CollectionUtils.isEmpty(list)) {
            LOGGER.error("getExinfo list is empty");
            throw new BusinessException("获取运单详情信息失败！");
        }

        List<DeReDetailVo> vos = new ArrayList<>();
        list.forEach(detail -> {
            DeReDetailVo vo = new DeReDetailVo();

            //获取司机信息
            CWaybillAddress cWaybillAddress = cWaybillAddressService.getByWaybillid(caybillId);
            if (null != cWaybillAddress) {
                vo.setAddr(cWaybillAddress.getDepartAddr());
                vo.setPhone(cWaybillAddress.getDepartPhone());
                vo.setContact(cWaybillAddress.getDepartContact());
            }

            //获取提车联系人信息
            List<CWaybillContacts> cWaybillContactsList = cWaybillContactsService.selectContacts(caybillId, WaybillContactsTypeEnum.DEPARTPERSON.getValue());
            CWaybillContacts cWaybillContacts = null;
            if (null != cWaybillContactsList) {
                cWaybillContacts = cWaybillContactsList.get(0);
            }
            if (null != cWaybillContacts) {
                vo.setDrivername(cWaybillContacts.getContact());
                vo.setDriverphone(cWaybillContacts.getPhone());
                vo.setDrivercardid(cWaybillContacts.getIdno());
                vo.setTracknumber(cWaybillContacts.getLicenseNumner());
            }

            //获取提车照片附件
            Long serviceOrderId = detail.getServiceOrderId();
            SServiceOrder serviceOrder = this.getSServiceOrderMapper().selectByPrimaryKey(serviceOrderId);
            if (serviceOrder != null && serviceOrder.getStatus() >= SServiceOrderStatusEnum.HAVE_EXTRACTED.getValue()) {
                List<CWaybillAttach> attachList = cWaybillAttachService.getByWaybillid(caybillId, AttachCategoryEnumWaybill.RECEIPT.getValue(), Arrays.asList(AttachTypeEnum.RECEIPT_BILL.getValue(), AttachTypeEnum.RECEIPT_PHOTO.getValue()));
                if (Collections3.isNotEmpty(attachList)) {
                    List<DeReDetailVo.Pic> pics = new ArrayList<>();
                    for (CWaybillAttach cWaybillAttach : attachList) {
                        DeReDetailVo.Pic pic = vo.new Pic();
                        pic.setPicurl(QiniuUtils.generateDownloadTicket(cWaybillAttach.getPicKey(), ""));
                        pics.add(pic);
                    }
                    vo.setPics(pics);
                }
            } else {
                vo.setPics(new ArrayList<DeReDetailVo.Pic>());
            }
            vos.add(vo);
        });

        return vos;
    }

    @Override
    public List<DeReDetailVo> getDeinfo(long caybillId) {
        LOGGER.info("getDeinfo param : {}", caybillId);
        if (0 == caybillId) {
            LOGGER.error("getDeinfo caybillId must not be 0");
            throw new IllegalArgumentException("运单id不能是0");
        }
        CWaybillDetailExample example = new CWaybillDetailExample();
        example.createCriteria().andWaybillIdEqualTo(caybillId);
        List<CWaybillDetail> list = cWaybillDetailMapper.selectByExample(example);
        if (CollectionUtils.isEmpty(list)) {
            LOGGER.error("getDeinfo list is empty");
            throw new BusinessException("获取运单详情信息失败！");
        }

        List<DeReDetailVo> vos = new ArrayList<>();
        list.forEach(detail -> {
            DeReDetailVo vo = new DeReDetailVo();

            //获取司机信息
            CWaybillAddress cWaybillAddress = cWaybillAddressService.getByWaybillid(caybillId);
            if (null != cWaybillAddress) {
                /** vo.setAddr( cWaybillAddress.getDepartAddr());
                 vo.setPhone( cWaybillAddress.getDepartPhone());
                 vo.setContact(cWaybillAddress.getDepartContact()); */
                vo.setAddr(cWaybillAddress.getReceiptAddr());
                vo.setPhone(cWaybillAddress.getReceiptPhone());
                vo.setContact(cWaybillAddress.getReceiptContact());
            }

            //获取交车联系人信息
            CWaybillContacts cWaybillContacts = cWaybillContactsService.selectContacts(caybillId, WaybillContactsTypeEnum.RECEIPTPERSON.getValue()).get(0);
            if (null != cWaybillContacts) {
                vo.setDrivername(cWaybillContacts.getContact());
                vo.setDriverphone(cWaybillContacts.getPhone());
                vo.setDrivercardid(cWaybillContacts.getIdno());
                vo.setTracknumber(cWaybillContacts.getLicenseNumner());
            }

            Long serviceOrderId = detail.getServiceOrderId();
            SServiceOrder serviceOrder = this.getSServiceOrderMapper().selectByPrimaryKey(serviceOrderId);
            //获取交车照片附件
            if (serviceOrder != null && serviceOrder.getStatus() >= SServiceOrderStatusEnum.HAVE_DELIVERY.getValue()) {
                List<CWaybillAttach> attachList = cWaybillAttachService.getByWaybillid(caybillId, AttachCategoryEnumWaybill.DELIVER.getValue(), Arrays.asList(AttachTypeEnum.DELIVER_BILL.getValue(), AttachTypeEnum.DELIVER_PHOTO.getValue()));
                if (Collections3.isNotEmpty(attachList)) {
                    List<DeReDetailVo.Pic> pics = new ArrayList<>();
                    for (CWaybillAttach cWaybillAttach : attachList) {
                        DeReDetailVo.Pic pic = vo.new Pic();
                        pic.setPicurl(QiniuUtils.generateDownloadTicket(cWaybillAttach.getPicKey(), ""));
                        pics.add(pic);
                    }
                    vo.setPics(pics);
                }
            } else {
                vo.setPics(new ArrayList<DeReDetailVo.Pic>());
            }
            vos.add(vo);
        });

        return vos;
    }

    /**
     * @param id
     * @return
     * @throws Exception
     * @Description 确认发车按钮 运单状态变为待交车WAITSTART
     */
    @Override
    public Long driverStart(Long id) {
        LOGGER.info("driver query start params id : {}.", id);
        try {
            // 获取当前登录用户
            UserVo userVo = this.getUserService().getCurrentUserVo();
            LOGGER.info("driver query start params id : {}, userVo : {}.", id, userVo);

            this.updateStatus(id, WaybillStatusEnum.WAITCOMPLETE.getValue(), SServiceOrderStatusEnum.HAVE_ISSUSD.getValue(), userVo);
        } catch (Exception e) {
            LOGGER.info("driver query start params id : {}, error : {}.", id, e);
            throw new BusinessException("司机确认发车异常");
        }
        return id;
    }

    @Override
    public BigDecimal proposedPrice(String depaCode, String depaAddr, String destCode, String destAddr, Date adate, int atime, List<Long> serviceOrderIds) {
        LOGGER.info("proposedPrice params : {}, {}, {}, {}, {}", depaCode, destCode, adate, atime, serviceOrderIds.size());
        if (StringUtils.isBlank(depaCode)) {
            LOGGER.error("proposedPrice depaCode must not be null");
            throw new IllegalArgumentException("起运地城市编码不能为空");
        }
        if (StringUtils.isBlank(depaAddr)) {
            LOGGER.error("proposedPrice depaAddr must not be null");
            throw new IllegalArgumentException("起运地详细地址不能为空");
        }
        if (StringUtils.isBlank(depaCode)) {
            LOGGER.error("proposedPrice depaCode must not be null");
            throw new IllegalArgumentException("起运地城市编码不能为空");
        }
        if (StringUtils.isBlank(destAddr)) {
            LOGGER.error("proposedPrice destAddr must not be null");
            throw new IllegalArgumentException("目的地详细地址编码不能为空");
        }
        if (CollectionUtils.isEmpty(serviceOrderIds)) {
            LOGGER.error("proposedPrice serviceOrderIds must not be null");
            throw new IllegalArgumentException("服务订单id不能为空");
        }

        //查询服务订单车辆信息
        List<SServiceOrderVehicleVo> vehicles = sServiceOrderVehicleService.getListBySOrderIds(serviceOrderIds);
//		total = BigDecimal.valueOf(vehicles.stream().mapToLong(vehicle -> feesService.queryFee(depaCode, destCode, vehicle.getSysVehicleClass(), vehicle.getEstValue(), vehicle.getAmount(), false, false, false).longValue()).sum());

        //查询服务订单的运输费和发票税费
        BFeeModel feeModel;
        List<BFeeType> bFeeTypes;

        SServiceOrderVehicleVo orderVehicleVo = vehicles.get(0);
        if (orderVehicleVo.getIsVeneer()) {
            feeModel = bFeeModelService.getByCode(BFeeModelEnum.CITYWIDE_ORDER);
            bFeeTypes = bFeeTypeService.getByCode(feeModel.getId(), Arrays.asList(BFeeTypeEnum.STARTING_PRICE.getValue(), BFeeTypeEnum.KM.getValue(), BFeeTypeEnum.TRAILER.getValue()));
        } else {
            feeModel = bFeeModelService.getByCode(BFeeModelEnum.INTERCITY_ORDER);
            bFeeTypes = bFeeTypeService.getByCode(feeModel.getId(), Arrays.asList(BFeeTypeEnum.SHIPPING.getValue(), BFeeTypeEnum.INVOICE_TAX.getValue()));
        }
        List<SServiceOrderFeedetail> feedetails = sServiceOrderFeedetailService.getList(serviceOrderIds, bFeeTypes.stream().map(type -> type.getId()).collect(Collectors.toList()));

        BigDecimal sum = BigDecimal.valueOf(feedetails.stream().mapToLong(vo -> vo.getActualAmount().longValue()).sum());

        //匹配配置模型
        if (!orderVehicleVo.getIsVeneer()) {
            List<Long> vehicleClassIds = vehicles.stream().map(detail -> detail.getSysVehicleClassid()).collect(Collectors.toList());
            List<Integer> vehicleNum = vehicles.stream().mapToInt(detail -> detail.getAmount()).collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
            BStowageModel model = bStowageVehicleService.computeSuitableStowage(BStowageModelEnum.WAYBILL, vehicleClassIds, vehicleNum);
            if (null != model) {
                //满足匹配模型-->打折
                sum = sum.multiply(model.getDiscount());
            }
        }

        return sum;
    }

    @Override
    public int updatePayStatus(Long waybillId) {
        LOGGER.info("update cwaybill paystatus params waybillId : {}.", waybillId);
        try {
            CWaybill cWaybill = new CWaybill();
            cWaybill.setId(waybillId);
            cWaybill.setPayStatus(PaymentStatusEnum.ALREADY_PAID.getValue());
            return this.getCWaybillMapper().updateByPrimaryKeySelective(cWaybill);
        } catch (Exception e) {
            LOGGER.error("update cwaybill paystatus params waybillId : {}, error : {}.", waybillId, e);
            throw new BusinessException("修改运单支付状态异常");
        }
    }

}